From 4bbd6b8a83956ce1568ef1aedc9489511c6ef66e Mon Sep 17 00:00:00 2001 From: Robert Vokac Date: Sat, 17 Dec 2022 15:32:48 +0100 Subject: [PATCH] NANOBOOT-1 : Import of files to Git --- CREDITS | 16 + LICENSE | 502 ++++++++++++++ README.md | 1 + build.sh | 1 + db-migration-core/pom.xml | 214 ++++++ db-migration-core/src/main/java/lombok.config | 4 + .../src/main/java/module-info.java | 35 + .../core/configuration/Configuration.java | 208 ++++++ .../configuration/ConfigurationEntry.java | 60 ++ .../core/configuration/ConfigurationKeys.java | 41 ++ .../core/entity/DBMigrationSchemaHistory.java | 107 +++ .../dbmigration/core/main/DBMigration.java | 461 +++++++++++++ .../core/main/DBMigrationException.java | 43 ++ .../core/main/DBMigrationTarget.java | 29 + .../core/main/MigrationResult.java | 30 + .../dbmigration/core/main/MigrationType.java | 29 + .../dbmigration/core/main/RepairResult.java | 29 + .../dbmigration/core/main/SqlMigration.java | 29 + .../api/DBMigrationPersistence.java | 48 ++ .../impl/base/DBMigrationPersistenceBase.java | 303 +++++++++ .../DBMigrationPersistenceSqliteImpl.java | 140 ++++ .../query/DBMigrationSchemaHistoryTable.java | 50 ++ .../resources/FileSystemSqlFileProvider.java | 58 ++ .../resources/ResourcesSqlFileProvider.java | 149 ++++ .../dbmigration/core/resources/SqlFile.java | 51 ++ .../core/resources/SqlFileName.java | 107 +++ .../core/resources/SqlFileProvider.java | 37 + .../core/resources/SqlFileVersion.java | 82 +++ .../core/utils/DBMigrationConstants.java | 34 + .../core/utils/DBMigrationUtils.java | 88 +++ .../src/main/resources/log4j2-example.xml | 28 + .../src/main/resources/log4j2.xml | 28 + .../configuration/ConfigurationEntryTest.java | 100 +++ .../configuration/ConfigurationTest.java | 637 ++++++++++++++++++ .../entity/DBMigrationSchemaHistoryTest.java | 157 +++++ .../FileSystemSqlFileProviderTest.java | 118 ++++ .../ResourcesSqlFileProviderTest.java | 113 ++++ .../resources/SqlFileNameTest.java | 399 +++++++++++ .../resources/SqlFileProviderTest.java | 83 +++ .../dbmigration/resources/SqlFileTest.java | 100 +++ .../utils/DBMigrationUtilsTest.java | 95 +++ db-migration-test-jar/pom.xml | 210 ++++++ .../src/main/java/lombok.config | 4 + .../src/main/java/module-info.java | 35 + .../jar/DBMigrationTestJarDummyClass.java | 29 + .../test/V000001_1__add_column_column1.sql | 2 + .../test/V000001__create_table_test1.sql | 7 + .../test/V000002_0__add_column_column1.sql | 2 + .../test/V000002_1__add_column_column1.sql | 2 + .../test/V000002_2__add_column_column1.sql | 2 + .../test/V000002_3__add_column_column1.sql | 2 + .../test/V000002_4__add_column_column1.sql | 2 + .../test/V000002_5__add_column_column1.sql | 2 + .../test/V000009__add_column_column1.sql | 2 + .../test/V000010__add_column_column1.sql | 2 + .../test/V000011__add_column_column1.sql | 2 + .../test/V000012__add_column_column1.sql | 2 + db-migration-test-jar/src/test/java/.gitkeep | 1 + pom.xml | 68 ++ release.sh | 99 +++ test.sh | 15 + 61 files changed, 5334 insertions(+) create mode 100644 CREDITS create mode 100755 LICENSE create mode 100644 README.md create mode 100755 build.sh create mode 100644 db-migration-core/pom.xml create mode 100644 db-migration-core/src/main/java/lombok.config create mode 100644 db-migration-core/src/main/java/module-info.java create mode 100644 db-migration-core/src/main/java/org/dbmigration/core/configuration/Configuration.java create mode 100644 db-migration-core/src/main/java/org/dbmigration/core/configuration/ConfigurationEntry.java create mode 100644 db-migration-core/src/main/java/org/dbmigration/core/configuration/ConfigurationKeys.java create mode 100644 db-migration-core/src/main/java/org/dbmigration/core/entity/DBMigrationSchemaHistory.java create mode 100755 db-migration-core/src/main/java/org/dbmigration/core/main/DBMigration.java create mode 100644 db-migration-core/src/main/java/org/dbmigration/core/main/DBMigrationException.java create mode 100644 db-migration-core/src/main/java/org/dbmigration/core/main/DBMigrationTarget.java create mode 100644 db-migration-core/src/main/java/org/dbmigration/core/main/MigrationResult.java create mode 100644 db-migration-core/src/main/java/org/dbmigration/core/main/MigrationType.java create mode 100644 db-migration-core/src/main/java/org/dbmigration/core/main/RepairResult.java create mode 100644 db-migration-core/src/main/java/org/dbmigration/core/main/SqlMigration.java create mode 100644 db-migration-core/src/main/java/org/dbmigration/core/persistence/api/DBMigrationPersistence.java create mode 100644 db-migration-core/src/main/java/org/dbmigration/core/persistence/impl/base/DBMigrationPersistenceBase.java create mode 100644 db-migration-core/src/main/java/org/dbmigration/core/persistence/impl/sqlite/DBMigrationPersistenceSqliteImpl.java create mode 100644 db-migration-core/src/main/java/org/dbmigration/core/query/DBMigrationSchemaHistoryTable.java create mode 100644 db-migration-core/src/main/java/org/dbmigration/core/resources/FileSystemSqlFileProvider.java create mode 100644 db-migration-core/src/main/java/org/dbmigration/core/resources/ResourcesSqlFileProvider.java create mode 100644 db-migration-core/src/main/java/org/dbmigration/core/resources/SqlFile.java create mode 100644 db-migration-core/src/main/java/org/dbmigration/core/resources/SqlFileName.java create mode 100644 db-migration-core/src/main/java/org/dbmigration/core/resources/SqlFileProvider.java create mode 100644 db-migration-core/src/main/java/org/dbmigration/core/resources/SqlFileVersion.java create mode 100644 db-migration-core/src/main/java/org/dbmigration/core/utils/DBMigrationConstants.java create mode 100644 db-migration-core/src/main/java/org/dbmigration/core/utils/DBMigrationUtils.java create mode 100644 db-migration-core/src/main/resources/log4j2-example.xml create mode 100644 db-migration-core/src/main/resources/log4j2.xml create mode 100644 db-migration-core/src/test/java/org/nanoboot/dbmigration/configuration/ConfigurationEntryTest.java create mode 100644 db-migration-core/src/test/java/org/nanoboot/dbmigration/configuration/ConfigurationTest.java create mode 100644 db-migration-core/src/test/java/org/nanoboot/dbmigration/entity/DBMigrationSchemaHistoryTest.java create mode 100644 db-migration-core/src/test/java/org/nanoboot/dbmigration/resources/FileSystemSqlFileProviderTest.java create mode 100644 db-migration-core/src/test/java/org/nanoboot/dbmigration/resources/ResourcesSqlFileProviderTest.java create mode 100644 db-migration-core/src/test/java/org/nanoboot/dbmigration/resources/SqlFileNameTest.java create mode 100644 db-migration-core/src/test/java/org/nanoboot/dbmigration/resources/SqlFileProviderTest.java create mode 100644 db-migration-core/src/test/java/org/nanoboot/dbmigration/resources/SqlFileTest.java create mode 100644 db-migration-core/src/test/java/org/nanoboot/dbmigration/utils/DBMigrationUtilsTest.java create mode 100644 db-migration-test-jar/pom.xml create mode 100644 db-migration-test-jar/src/main/java/lombok.config create mode 100644 db-migration-test-jar/src/main/java/module-info.java create mode 100644 db-migration-test-jar/src/main/java/org/nanoboot/dbmigration/test/jar/DBMigrationTestJarDummyClass.java create mode 100644 db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000001_1__add_column_column1.sql create mode 100644 db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000001__create_table_test1.sql create mode 100644 db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000002_0__add_column_column1.sql create mode 100644 db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000002_1__add_column_column1.sql create mode 100644 db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000002_2__add_column_column1.sql create mode 100644 db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000002_3__add_column_column1.sql create mode 100644 db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000002_4__add_column_column1.sql create mode 100644 db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000002_5__add_column_column1.sql create mode 100644 db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000009__add_column_column1.sql create mode 100644 db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000010__add_column_column1.sql create mode 100644 db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000011__add_column_column1.sql create mode 100644 db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000012__add_column_column1.sql create mode 100644 db-migration-test-jar/src/test/java/.gitkeep create mode 100644 pom.xml create mode 100755 release.sh create mode 100755 test.sh diff --git a/CREDITS b/CREDITS new file mode 100644 index 0000000..0490074 --- /dev/null +++ b/CREDITS @@ -0,0 +1,16 @@ + This file partially lists people, that have contributed to + the "DB Migration" project. They are sorted by name. + The fields are: name (N), e-mail (E), web-address (W), + PGP key ID and fingerprint (P), description (D) and + snail-mail address (S). + Thanks, + + Vokac +---------- + +N: Robert Vokac +E: robertvokac@nanoboot.org +W: https://nanoboot.org +P: 4096R/E3329055 322B D109 0AA8 C324 EA9C 72F5 693D 30BE E332 9055 +D: Founder +S: Czech Republic diff --git a/LICENSE b/LICENSE new file mode 100755 index 0000000..4362b49 --- /dev/null +++ b/LICENSE @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/README.md b/README.md new file mode 100644 index 0000000..d14f357 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# db-migration diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..b39292e --- /dev/null +++ b/build.sh @@ -0,0 +1 @@ +mvn clean install diff --git a/db-migration-core/pom.xml b/db-migration-core/pom.xml new file mode 100644 index 0000000..a189074 --- /dev/null +++ b/db-migration-core/pom.xml @@ -0,0 +1,214 @@ + + + + 4.0.0 + + + org.nanoboot.tools.dbmigration + db-migration + 0.1.0-SNAPSHOT + + + org.nanoboot.tools.dbmigration + db-migration-core + jar + + DB Migration Core + Tool migrating databases versions. + + + + + + + + + + org.apache.maven.plugins + maven-deploy-plugin + ${maven-deploy-plugin.version} + + + + + + org.jacoco + jacoco-maven-plugin + ${jacoco-maven-plugin.version} + + + + prepare-agent + + + + + report + test + + report + + + + + + org.apache.maven.plugins + maven-assembly-plugin + ${maven-assembly-plugin.version} + + + + org.nanoboot.dbmigration.core.main.DBMigration + + + + jar-with-dependencies + + + + + make-assembly + package + + single + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + ${checkstyle.skip} + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + + + + org.projectlombok + lombok + ${lombok.version} + + + ${javase.version} + ${javase.version} + + + + maven-surefire-plugin + ${maven-surefire-plugin.version} + + + maven-failsafe-plugin + ${maven-surefire-plugin.version} + + + + + + + org.flywaydb + flyway-core + ${flyway-core.version} + + + + org.projectlombok + lombok + ${lombok.version} + provided + + + org.xerial + sqlite-jdbc + ${sqlite-jdbc.version} + + + + org.nanoboot.powerframework + power-time + ${power.version} + + + org.nanoboot.powerframework + power-core + ${power.version} + + + org.nanoboot.powerframework + power-security + ${power.version} + + + org.apache.logging.log4j + log4j-api + ${log4j.version} + + + + org.apache.logging.log4j + log4j-core + ${log4j.version} + + + + org.junit.jupiter + junit-jupiter-api + ${junit-jupiter.version} + test + + + org.junit.jupiter + junit-jupiter-engine + ${junit-jupiter.version} + test + + + org.junit.jupiter + junit-jupiter-params + ${junit-jupiter.version} + test + + + + org.mockito + mockito-inline + ${mockito-inline.version} + test + + + org.nanoboot.tools.dbmigration + db-migration-test-jar + ${dbmigration.version} + test + + + + + diff --git a/db-migration-core/src/main/java/lombok.config b/db-migration-core/src/main/java/lombok.config new file mode 100644 index 0000000..b6d6306 --- /dev/null +++ b/db-migration-core/src/main/java/lombok.config @@ -0,0 +1,4 @@ +# tells Lombok that this is the root directory and that it shouldn’t search parent directories for more configuration files +config.stopBubbling = true +# tells Lombok to add @lombok.Generated annotation to all generated methods +lombok.addLombokGeneratedAnnotation = true diff --git a/db-migration-core/src/main/java/module-info.java b/db-migration-core/src/main/java/module-info.java new file mode 100644 index 0000000..cdf0413 --- /dev/null +++ b/db-migration-core/src/main/java/module-info.java @@ -0,0 +1,35 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +module dbmigration.core { + requires org.flywaydb.core; + requires lombok; + requires java.sql; + requires powerframework.time; + requires powerframework.core; + requires powerframework.security; + requires org.apache.logging.log4j; + requires org.apache.logging.log4j.core; + exports org.nanoboot.dbmigration.core.main; +} diff --git a/db-migration-core/src/main/java/org/dbmigration/core/configuration/Configuration.java b/db-migration-core/src/main/java/org/dbmigration/core/configuration/Configuration.java new file mode 100644 index 0000000..3ff9e65 --- /dev/null +++ b/db-migration-core/src/main/java/org/dbmigration/core/configuration/Configuration.java @@ -0,0 +1,208 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.configuration; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.nanoboot.dbmigration.core.main.DBMigrationException; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +public class Configuration { + + private static final Logger LOG = LogManager.getLogger(Configuration.class); + + private Map map = new HashMap<>(); + + public static void validateKey(String key) { + if (!startsKeyWithPrefix(key)) { + String msg = "Key does not start with prefix " + ConfigurationKeys.PROPERTIES_PREFIX; + LOG.error(msg); + throw new DBMigrationException(msg); + } + } + + public static boolean startsKeyWithPrefix(String key) { + return key.startsWith(ConfigurationKeys.PROPERTIES_PREFIX); + } + + public static String prependPrefixIfNeeded(String key) { + if (!startsKeyWithPrefix(key)) { + return ConfigurationKeys.PROPERTIES_PREFIX + key; + } + return key; + } + + public void add(ConfigurationEntry configurationEntry) { + add(configurationEntry.getKey(), configurationEntry.getValue()); + } + + public void add(String key, String value) { + validateKey(key); + if (value == null) { + //nothing to do + LOG.debug("Trying to add key {} with value. Skipping. Null values are skipped.", key); + return; + } + LOG.debug("Added key: \"{}\" with value \"{}\".", key, value); + this.map.put(key, value); + } + + public void addAndAddPrefixIfNeeded(ConfigurationEntry configurationEntry) { + configurationEntry.setKey(prependPrefixIfNeeded(configurationEntry.getKey())); + add(configurationEntry); + } + + public void addAndAddPrefixIfNeeded(String key, String value) { + add(prependPrefixIfNeeded(key), value); + } + + public String get(String key) { + validateKey(key); + return getMandatory(key); + } + + public String getMandatory(String key) { + if (!has(key)) { + final String msg = "There is no key: " + key; + LOG.error(msg); + throw new DBMigrationException(msg); + } + return map.get(key); + } + + public String getOptional(String key) { + validateKey(key); + + if (!has(key)) { + final String msg = "There is no key: " + key; + LOG.warn(msg); + + return null; + } + return map.get(key); + } + + public boolean has(String key) { + validateKey(key); + return map.containsKey(key); + } + + public void remove(String key) { + validateKey(key); + map.remove(key); + } + + public List listKeys() { + List list = new ArrayList<>(); + for (String key : map.keySet()) { + list.add(key); + } + return list; + } + + public List list() { + List list = new ArrayList<>(); + for (String key : map.keySet()) { + String value = get(key); + list.add(new ConfigurationEntry(key, value)); + } + return list; + } + + public String getDatasourceJdbcUrl() { + return get(ConfigurationKeys.DATASOURCE_JDBC_URL); + } + + public void setDatasourceJdbcUrl(String datasourceJdbcUrl) { + add(ConfigurationKeys.DATASOURCE_JDBC_URL, datasourceJdbcUrl); + } + + public String getDatasourceUser() { + return getOptional(ConfigurationKeys.DATASOURCE_USER); + } + + public void setDatasourceUser(String datasourceUser) { + add(ConfigurationKeys.DATASOURCE_USER, datasourceUser); + } + + public String getDatasourcePassword() { + return getOptional(ConfigurationKeys.DATASOURCE_PASSWORD); + } + + public void setDatasourcePassword(String datasourcePassword) { + add(ConfigurationKeys.DATASOURCE_PASSWORD, datasourcePassword); + } + + public String getName() { + return get(ConfigurationKeys.NAME); + } + + public void setName(String name) { + add(ConfigurationKeys.NAME, name); + } + + public String getSqlDialect() { + return get(ConfigurationKeys.SQL_DIALECT); + } + + public void setSqlDialect(String sqlDialect) { + add(ConfigurationKeys.SQL_DIALECT, sqlDialect); + } + + public String getSqlDialectImplClass() { + return get(ConfigurationKeys.SQL_DIALECT_IMPL_CLASS); + } + + public void setSqlDialectImplClass(String sqlDialectImplClass) { + add(ConfigurationKeys.SQL_DIALECT_IMPL_CLASS, sqlDialectImplClass); + } + + public String getSqlMigrationsDirectory() { + return getOptional(ConfigurationKeys.SQL_MIGRATIONS_DIRECTORY); + } + + public void setSqlMigrationsDirectory(String sqlMigrationsDirectory) { + add(ConfigurationKeys.SQL_MIGRATIONS_DIRECTORY, sqlMigrationsDirectory); + } + + public String getSqlMigrationsClass() { + return getOptional(ConfigurationKeys.SQL_MIGRATIONS_CLASS); + } + + public void setSqlMigrationsClass(String sqlMigrationsClass) { + add(ConfigurationKeys.SQL_MIGRATIONS_CLASS, sqlMigrationsClass); + } + + public String getInstalledBy() { + return get(ConfigurationKeys.INSTALLED_BY); + } + + public void setInstalledBy(String installedBy) { + add(ConfigurationKeys.INSTALLED_BY, installedBy); + } +} diff --git a/db-migration-core/src/main/java/org/dbmigration/core/configuration/ConfigurationEntry.java b/db-migration-core/src/main/java/org/dbmigration/core/configuration/ConfigurationEntry.java new file mode 100644 index 0000000..8a4e15b --- /dev/null +++ b/db-migration-core/src/main/java/org/dbmigration/core/configuration/ConfigurationEntry.java @@ -0,0 +1,60 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.configuration; + +import lombok.AllArgsConstructor; +import lombok.Data; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.nanoboot.dbmigration.core.main.DBMigrationException; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +@Data +@AllArgsConstructor +public class ConfigurationEntry { + + private static final Logger LOG = LogManager.getLogger(ConfigurationEntry.class); + + private String key; + private String value; + + public static ConfigurationEntry ofArgument(String arg) { + if (!arg.startsWith("-")) { + String msg = "Arguments must start with - since second position: " + arg; + LOG.error(msg); + throw new DBMigrationException(msg); + } + String tmpArg = arg.substring(1); + String[] array = tmpArg.split("=", 2); + if (array.length != 2) { + String msg = "Array is " + array.length + ", but 2 was expected."; + LOG.error(msg); + throw new DBMigrationException(msg); + } + String key = array[0]; + String value = array[1]; + + return new ConfigurationEntry(key, value); + } +} diff --git a/db-migration-core/src/main/java/org/dbmigration/core/configuration/ConfigurationKeys.java b/db-migration-core/src/main/java/org/dbmigration/core/configuration/ConfigurationKeys.java new file mode 100644 index 0000000..2a4ac52 --- /dev/null +++ b/db-migration-core/src/main/java/org/dbmigration/core/configuration/ConfigurationKeys.java @@ -0,0 +1,41 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.configuration; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +public class ConfigurationKeys { + public static final String PROPERTIES_PREFIX = "dbmigration."; + public static final String DATASOURCE_JDBC_URL = "dbmigration.datasource.jdbc-url"; + public static final String DATASOURCE_USER = "dbmigration.datasource.user"; + public static final String DATASOURCE_PASSWORD = "dbmigration.datasource.password"; + public static final String NAME = "dbmigration.name"; + public static final String SQL_DIALECT = "dbmigration.sql-dialect"; + public static final String SQL_DIALECT_IMPL_CLASS = "dbmigration.sql-dialect-impl-class"; + public static final String SQL_MIGRATIONS_DIRECTORY = "dbmigration.sql-migrations-directory"; + public static final String SQL_MIGRATIONS_CLASS = "dbmigration.sql-migrations-class"; + public static final String INSTALLED_BY = "dbmigration.installed-by"; + private ConfigurationKeys() { + //Not meant to be instantiated. + } +} diff --git a/db-migration-core/src/main/java/org/dbmigration/core/entity/DBMigrationSchemaHistory.java b/db-migration-core/src/main/java/org/dbmigration/core/entity/DBMigrationSchemaHistory.java new file mode 100644 index 0000000..f42060e --- /dev/null +++ b/db-migration-core/src/main/java/org/dbmigration/core/entity/DBMigrationSchemaHistory.java @@ -0,0 +1,107 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.entity; + +import java.io.UnsupportedEncodingException; +import java.security.NoSuchAlgorithmException; +import java.util.UUID; +import lombok.Data; +import lombok.ToString; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.nanoboot.dbmigration.core.main.DBMigrationException; +import org.nanoboot.dbmigration.core.main.MigrationType; +import org.nanoboot.dbmigration.core.utils.DBMigrationUtils; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +@Data +@ToString +public class DBMigrationSchemaHistory implements Comparable { + + private static final Logger LOG = LogManager.getLogger(DBMigrationSchemaHistory.class); + /** + * UUID of migration. + */ + private UUID id; + /** + * Migration group. + */ + private String migrationGroup; + /** + * Order number. + */ + private int installedRank; + /** + * Version. examples: 1, 1.0, 4.3.5 + */ + private String version; + /** + * Description extracted from script name. + */ + private String description; + /** + * Migration type: SQL or Java + */ + private MigrationType type; + /** + * Script name + */ + private String script; + /** + * Hash. + */ + private String hash; + /** + * Installation was done by. + */ + private String installedBy; + /** + * Installation date and time. + */ + private String installedOn; + /** + * Installation time. + */ + private int executionTime; + /** + * Result. If success, then true, otherwise false (failure). + */ + //in milliseconds + private boolean success; + + public static String calculateHash(String hashOfPreviousMigration, String hashOfScriptContentOfThisMigration) { + return DBMigrationUtils.hashSha1(hashOfPreviousMigration + hashOfScriptContentOfThisMigration); + } + + @Override + public int compareTo(DBMigrationSchemaHistory o) { + if (!this.getMigrationGroup().equals(o.getMigrationGroup())) { + String msg = "Cannot compare, if migration groups are different: this.getMigrationGroup()={}, o.getMigrationGroup()={}"; + LOG.error(msg, this.getMigrationGroup(), o.getMigrationGroup()); + throw new DBMigrationException(DBMigrationUtils.formatString(msg, this.getMigrationGroup(), o.getMigrationGroup())); + } + return Integer.valueOf(this.getInstalledRank()).compareTo(Integer.valueOf(o.getInstalledRank())); + } + +} diff --git a/db-migration-core/src/main/java/org/dbmigration/core/main/DBMigration.java b/db-migration-core/src/main/java/org/dbmigration/core/main/DBMigration.java new file mode 100755 index 0000000..7596be7 --- /dev/null +++ b/db-migration-core/src/main/java/org/dbmigration/core/main/DBMigration.java @@ -0,0 +1,461 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.main; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.apache.logging.log4j.LogManager; +import org.nanoboot.dbmigration.core.configuration.Configuration; +import org.nanoboot.dbmigration.core.configuration.ConfigurationEntry; +import org.nanoboot.dbmigration.core.configuration.ConfigurationKeys; +import org.nanoboot.dbmigration.core.entity.DBMigrationSchemaHistory; +import org.nanoboot.dbmigration.core.resources.SqlFile; +import org.nanoboot.dbmigration.core.persistence.api.DBMigrationPersistence; +import org.nanoboot.dbmigration.core.query.DBMigrationSchemaHistoryTable; +import org.nanoboot.dbmigration.core.resources.FileSystemSqlFileProvider; +import org.nanoboot.dbmigration.core.resources.ResourcesSqlFileProvider; +import org.nanoboot.dbmigration.core.resources.SqlFileVersion; +import org.nanoboot.powerframework.time.duration.StopWatch; +import org.nanoboot.powerframework.time.moment.UniversalDateTime; +import org.nanoboot.powerframework.time.utils.TimeUnit; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +public class DBMigration { + + private static final org.apache.logging.log4j.Logger LOG = LogManager.getLogger(DBMigration.class); + + private void info() { + LOG.info("*** Target : info : START ***"); + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + public static class FluentConfiguration { + + private final Configuration configuration = new Configuration(); + + public DBMigration load() { + return new DBMigration(configuration); + } + + public FluentConfiguration dataSource(String jdbcUrl) { + return dataSource(jdbcUrl, null, null); + } + + public FluentConfiguration dataSource(String jdbcUrl, String user, String password) { + configuration.add(ConfigurationKeys.DATASOURCE_JDBC_URL, jdbcUrl); + configuration.add(ConfigurationKeys.DATASOURCE_USER, user); + configuration.add(ConfigurationKeys.DATASOURCE_PASSWORD, password); + return this; + } + + public FluentConfiguration name(String name) { + configuration.add(ConfigurationKeys.NAME, name); + return this; + } + + public FluentConfiguration sqlDialect(String sqlDialect, String sqlDialectImplClass) { + configuration.add(ConfigurationKeys.SQL_DIALECT, sqlDialect); + configuration.add(ConfigurationKeys.SQL_DIALECT_IMPL_CLASS, sqlDialectImplClass); + return this; + } + + public FluentConfiguration sqlMigrationsDirectory(String sqlMigrationsDirectory) { + configuration.add(ConfigurationKeys.SQL_MIGRATIONS_DIRECTORY, sqlMigrationsDirectory); + return this; + } + + public FluentConfiguration sqlMigrationsClass(String sqlMigrationsClass) { + configuration.add(ConfigurationKeys.SQL_MIGRATIONS_CLASS, sqlMigrationsClass); + return this; + } + + public FluentConfiguration installedBy(String installedBy) { + configuration.add(ConfigurationKeys.INSTALLED_BY, installedBy); + return this; + } + + } + private final Configuration configuration; + private final DBMigrationPersistence persistence; + + //validate -datasource.jdbc-url=jdbc:sqlite:/home/robertvokac/Desktop/test.sqlite3 -name=testDev -sql-dialect=sqlite -sql-migrations-directory=/home/robertvokac/Desktop/testDev/ -installed-by=robertvokac -sql-dialect-impl-class=org.nanoboot.dbmigration.persistence.impl.sqlite.DBMigrationPersistenceSqliteImpl + public static void main(String[] args) { + LOG.info("*** DB Migration ***"); + LOG.info("DB Migration main static method has just started."); + //Flyway flyway = Flyway.configure().dataSource("jdbc:h2:file:./target/foobar", "sa", null).load(); + Configuration configuration = new Configuration(); + if (args.length == 0) { + final String msg = "There must be at least one argument, but none was defined."; + LOG.error(msg); + throw new DBMigrationException(msg); + } + String target = args[0]; + DBMigrationTarget.valueOf(target.toUpperCase()); + LOG.info("Requested target = {}", target); + for (int i = 1; i < args.length; i++) { + if (args.length == 1) { + break; + } + String arg = args[i];; + LOG.debug("Found arg \"" + arg + "\""); + configuration.addAndAddPrefixIfNeeded(ConfigurationEntry.ofArgument(arg)); + } + DBMigration dBMigration = new DBMigration(configuration); + //info -datasource.jdbc-url=jdbc:sqlite:/home/robertvokac/Desktop/test.sqlite3 -name=testDev -sql-dialect=sqlite -sql-migrations-directory=/home/robertvokac/Desktop/testDev/ -installed-by=robertvokac -sql-dialect-impl-class=org.nanoboot.dbmigration.core.persistence.impl.sqlite.DBMigrationPersistenceSqliteImpl +// DBMigration dBMigration = DBMigration.configure() +// .dataSource("jdbc:sqlite:/home/robertvokac/Desktop/test.sqlite3") +// .name("testDev") +// .sqlDialect("sqlite", "org.nanoboot.dbmigration.persistence.impl.sqlite.DBMigrationPersistenceSqliteImpl") +// .sqlMigrationsDirectory("/home/robertvokac/Desktop/testDev/") +// .installedBy("robertvokac") +// .load(); + LOG.info("Going to execute target (and all its predecessors): {}", target); + switch (target) { + case "test": + dBMigration.test(); + break; + case "info": + dBMigration.info(); + break; + case "validate": + dBMigration.validate(); + break; + case "migrate": + dBMigration.migrate(); + break; + case "repair": + dBMigration.repair(); + break; + default: + throw new DBMigrationException("Unknown target " + target); + } + //dBMigration.repair(); + //dBMigration.migrate(); + + } + + public static FluentConfiguration configure() { + return new FluentConfiguration(); + } + + public DBMigration(Configuration configurationIn) { + this.configuration = configurationIn; + try { + this.persistence = loadPersistence(); + this.persistence.setConfiguration(configurationIn); + } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { + ex.printStackTrace(); + throw new DBMigrationException(ex); + } + init(); + } + + private DBMigrationPersistence loadPersistence() + throws ClassNotFoundException, NoSuchMethodException, InstantiationException, + IllegalAccessException, IllegalArgumentException, InvocationTargetException { + Class clazz; + clazz = Class.forName(this.configuration.getSqlDialectImplClass()); + + Constructor constr = clazz.getConstructor(); + DBMigrationPersistence persistenceTemp = (DBMigrationPersistence) constr.newInstance(); + return persistenceTemp; + } + + private void init() { + + } + + public boolean validate() { + test(); + + LOG.info(" "); + LOG.info("*** Target : validate : START ***"); + + try { + + boolean doesSchemaTableExist = persistence.doesMigrationSchemaHistoryTableExist(); + LOG.debug("Schema table exists = {}", doesSchemaTableExist); + if (!doesSchemaTableExist) { + LOG.info("Going to create schema table {}", DBMigrationSchemaHistoryTable.TABLE_NAME); + persistence.createMigrationSchemaHistoryTable(); + } + List sqlFiles = loadSqlFiles(); + int nr = 0; + for (SqlFile sf : sqlFiles) { + nr++; + LOG.info("Found sql file to be applied: #{}: {}", nr, sf.getFileName()); + LOG.debug("This sql file {} has sha1 hash: {}", sf.getFileName(), sf.calculateHash()); + + } + List migrations = persistence.listMigrations(this.configuration.getName()); + LOG.info("Listing migrations for migration group with name: {}", this.configuration.getName()); + if (migrations.isEmpty()) { + LOG.warn("There is no migration for this group in Migration Schema table history."); + } + for (DBMigrationSchemaHistory m : migrations) { + LOG.info("Migration:"); + LOG.info("\t{} ", m); + + } + Set versions = new HashSet<>(); + + Map migrationsMap = new HashMap<>(); + Map sqlFilesMap = new HashMap<>(); + for (DBMigrationSchemaHistory m : migrations) { + versions.add(m.getVersion()); + migrationsMap.put(m.getVersion(), m); + } + for (SqlFile sf : sqlFiles) { + versions.add(sf.getSqlFileName().getVersion()); + sqlFilesMap.put(sf.getSqlFileName().getVersion(), sf); + } + for (DBMigrationSchemaHistory m : migrations) { + if (!sqlFilesMap.containsKey(m.getVersion())) { + DBMigrationException e = new DBMigrationException("There is script " + m.getScript() + " only in database but not in migration directory/jar"); + LOG.error(e.getMessage()); + throw e; + } + if (!m.isSuccess()) { + DBMigrationException e = new DBMigrationException("Migration " + m.getScript() + " has failure. Validation failed."); + LOG.error(e.getMessage()); + throw e; + } + } + + for (int i = 0; i < migrations.size(); i++) { + DBMigrationSchemaHistory migration = migrations.get(i); + SqlFile sqlFile = sqlFiles.get(i); + if (!migration.getVersion().equals(sqlFile.getSqlFileName().getVersion())) { + DBMigrationException e = new DBMigrationException("There is an additional sql file in migration directory " + sqlFile.getFileName() + "." + migration.getScript() + " was expected."); + LOG.error(e.getMessage()); + throw e; + } + String sqlFileHash = sqlFile.calculateHash(); + String migrationHash = migration.getHash(); + String previousMigrationHash; + if (i == 0) { + previousMigrationHash = ""; + } else { + DBMigrationSchemaHistory previousMigration = migrations.get(i - 1); + previousMigrationHash = previousMigration.getHash(); + } + String expectedMigrationHash = DBMigrationSchemaHistory.calculateHash(previousMigrationHash, sqlFileHash); + if (!migrationHash.equals(expectedMigrationHash)) { + final String msg = "Migration hash \"" + migrationHash + "\" is not that one, which was expected. Something is wrong (script " + migration.getScript() + "): sql file SHA-1 hash or migration SHA-1 hash."; + DBMigrationException e = new DBMigrationException(msg); + LOG.error(e.getMessage()); + throw e; + } + + } + List notYetMigratedSqlFiles = new ArrayList<>(); + for (String version : versions) { + if (!migrationsMap.containsKey(version)) { + notYetMigratedSqlFiles.add(sqlFilesMap.get(version)); + } + } + LOG.info("Going to check, which SQL scripts were not yet migrated:"); + LOG.info("Result: all SQL scripts were already migrated. There is nothing to migrate."); + for (SqlFile sqlFile : sqlFiles) { + if (notYetMigratedSqlFiles.contains(sqlFile)) { + LOG.warn("Following SQL script was not yet migrated: {}", sqlFile.getFileName()); + } + } + + } catch (Exception e) { + DBMigrationException dBMigrationException = new DBMigrationException("Target validate failed while running", e); + LOG.error(dBMigrationException); + throw dBMigrationException; + } + + return true; + } + + private List loadSqlFiles() { + List sqlFiles; + LOG.info("Going to load sql migrations files to be applied:"); + String sqlMigrationsDirectory = configuration.getSqlMigrationsDirectory(); + if (sqlMigrationsDirectory == null) { + LOG.info("Sql migrations files from a jar file will be used."); + String path = ResourcesSqlFileProvider + .createPath( + configuration.getSqlDialect(), + configuration.getName()); + Class clazz; + String className = configuration.getSqlMigrationsClass(); + try { + LOG.debug("Going to create class object for: {}", className); + clazz = Class.forName(className); + LOG.debug("Creating class {} was success", className); + } catch (ClassNotFoundException ex) { + LOG.error("Creating class {} failed: {}", className, ex.getMessage()); + Logger.getLogger(DBMigration.class.getName()).log(Level.SEVERE, null, ex); + throw new DBMigrationException(ex); + } + sqlFiles = new ResourcesSqlFileProvider().provide(path, clazz); + + } else { + LOG.info("Sql migrations files from a directory file will be used."); + sqlFiles = new FileSystemSqlFileProvider().provide(sqlMigrationsDirectory); + } + Collections.sort(sqlFiles); + return sqlFiles; + } + + public MigrationResult migrate() { + validate(); + LOG.info(" "); + LOG.info("*** Target : migrate : START ***"); + + try { + + List sqlFiles = loadSqlFiles(); + List migrations = persistence.listMigrations(this.configuration.getName()); + + List sqlFileVersions = new ArrayList<>(); + + Map migrationsMap = new HashMap<>(); + Map sqlFilesMap = new HashMap<>(); + for (DBMigrationSchemaHistory m : migrations) { + sqlFileVersions.add(new SqlFileVersion(m.getVersion())); + migrationsMap.put(m.getVersion(), m); + } + for (SqlFile sf : sqlFiles) { + sqlFileVersions.add(new SqlFileVersion(sf.getSqlFileName().getVersion())); + sqlFilesMap.put(sf.getSqlFileName().getVersion(), sf); + } + + Collections.sort(sqlFileVersions); + + int countOfExecutedMigrations = 0; + for (SqlFileVersion sqlFileVersion : sqlFileVersions) { + String version = sqlFileVersion.getVersion(); + if (!migrationsMap.containsKey(version)) { + countOfExecutedMigrations++; + LOG.info("Going to migrate SQL script {}.", sqlFilesMap.get(version).getFileName()); + SqlFile sqlFile = sqlFilesMap.get(version); + DBMigrationSchemaHistory newMigration = new DBMigrationSchemaHistory(); + newMigration.setId(UUID.randomUUID()); + newMigration.setMigrationGroup(configuration.getName()); + DBMigrationSchemaHistory previousMigration = migrations.isEmpty() ? null : migrations.get(migrations.size() - 1); + + int newInstalledRank = previousMigration == null ? 1 : previousMigration.getInstalledRank() + 1; + LOG.debug("previousMigration is {} and new rank is {}", previousMigration, newInstalledRank); + newMigration.setInstalledRank(newInstalledRank); + newMigration.setVersion(sqlFile.getSqlFileName().getVersion()); + newMigration.setDescription(sqlFile.getSqlFileName().getDescription()); + newMigration.setType(MigrationType.SQL); + newMigration.setScript(sqlFile.getFileName()); + String newHash = DBMigrationSchemaHistory.calculateHash(previousMigration == null ? "" : previousMigration.getHash(), sqlFile.calculateHash()); + newMigration.setHash(newHash); + newMigration.setInstalledBy(configuration.getInstalledBy()); + newMigration.setInstalledOn(UniversalDateTime.now().toString()); + newMigration.setExecutionTime(456); + newMigration.setSuccess(true); + + String sql = sqlFile.getContent(); + StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + String result = persistence.executeSql(sql); + stopWatch.stop(); + boolean success = result == null; + newMigration.setExecutionTime((int) stopWatch.getCurrentDuration().toTotal(TimeUnit.MILLISECOND)); + newMigration.setSuccess(success); + + if (success) { + LOG.info("Migration of script " + newMigration.getScript() + " Finished. Result: SUCCESS."); + } else { + LOG.error("Migration of script {} Finished. Result: FAILURE", newMigration.getScript()); + LOG.error("Migration of script {} with sql content: \n", newMigration.getScript(), sql); + LOG.error("Migration of script : " + "Error details: {}", result); + } + persistence.addMigration(newMigration); + migrations.add(newMigration); + if (!success) { + throw new DBMigrationException("INFO : Migration of script " + newMigration.getScript() + " Finished. Result: FAILURE"); + } + + } + } + LOG.info("Count of successfully executed migrations is {}", countOfExecutedMigrations); + return MigrationResult.SUCCESS; + } catch (Exception e) { + DBMigrationException dBMigrationException = new DBMigrationException("Target migrate failed while running", e); + LOG.error(dBMigrationException); + throw dBMigrationException; + } + + } + + public RepairResult repair() { + test(); + LOG.info(" "); + LOG.info("*** Target : repair : START ***"); + + try { + List migrations = persistence.listMigrations(this.configuration.getName()); + List failedMigrationsToBeRemoved = new ArrayList<>(); + for (DBMigrationSchemaHistory m : migrations) { + if (!m.isSuccess()) { + failedMigrationsToBeRemoved.add(m); + } + } + for (DBMigrationSchemaHistory m : failedMigrationsToBeRemoved) { + LOG.info("Going to remove migration: " + m.toString()); + persistence.removeMigration(m.getMigrationGroup(), m.getVersion()); + } + migrate(); + } catch (Exception e) { + DBMigrationException dBMigrationException = new DBMigrationException("Target repair failed while running", e); + LOG.error(dBMigrationException); + throw dBMigrationException; + } + + return RepairResult.SUCCESS; + } + + public boolean test() { + LOG.info(" "); + LOG.info("*** Target : test : START ***"); + try { + persistence.test(); + } catch (Exception e) { + DBMigrationException dBMigrationException = new DBMigrationException("Target test failed while running", e); + LOG.error(dBMigrationException); + throw dBMigrationException; + } + return true; + } + +} diff --git a/db-migration-core/src/main/java/org/dbmigration/core/main/DBMigrationException.java b/db-migration-core/src/main/java/org/dbmigration/core/main/DBMigrationException.java new file mode 100644 index 0000000..515264d --- /dev/null +++ b/db-migration-core/src/main/java/org/dbmigration/core/main/DBMigrationException.java @@ -0,0 +1,43 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.main; + +import java.io.UnsupportedEncodingException; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +public class DBMigrationException extends RuntimeException { + + public DBMigrationException(String msg, Exception ex) { + super(msg, ex); + } + + public DBMigrationException(String msg) { + super(msg); + } + + public DBMigrationException(Exception ex) { + super(ex); + } + +} diff --git a/db-migration-core/src/main/java/org/dbmigration/core/main/DBMigrationTarget.java b/db-migration-core/src/main/java/org/dbmigration/core/main/DBMigrationTarget.java new file mode 100644 index 0000000..c3a0eca --- /dev/null +++ b/db-migration-core/src/main/java/org/dbmigration/core/main/DBMigrationTarget.java @@ -0,0 +1,29 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.main; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +public enum DBMigrationTarget { + TEST, INFO, VALIDATE, MIGRATE, REPAIR; +} diff --git a/db-migration-core/src/main/java/org/dbmigration/core/main/MigrationResult.java b/db-migration-core/src/main/java/org/dbmigration/core/main/MigrationResult.java new file mode 100644 index 0000000..3786233 --- /dev/null +++ b/db-migration-core/src/main/java/org/dbmigration/core/main/MigrationResult.java @@ -0,0 +1,30 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.main; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +public enum MigrationResult { + SUCCESS, FAILURE; + +} diff --git a/db-migration-core/src/main/java/org/dbmigration/core/main/MigrationType.java b/db-migration-core/src/main/java/org/dbmigration/core/main/MigrationType.java new file mode 100644 index 0000000..07711df --- /dev/null +++ b/db-migration-core/src/main/java/org/dbmigration/core/main/MigrationType.java @@ -0,0 +1,29 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.main; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +public enum MigrationType { + SQL, JAVA; +} diff --git a/db-migration-core/src/main/java/org/dbmigration/core/main/RepairResult.java b/db-migration-core/src/main/java/org/dbmigration/core/main/RepairResult.java new file mode 100644 index 0000000..8653472 --- /dev/null +++ b/db-migration-core/src/main/java/org/dbmigration/core/main/RepairResult.java @@ -0,0 +1,29 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.main; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +public enum RepairResult { + SUCCESS, FAILURE; +} diff --git a/db-migration-core/src/main/java/org/dbmigration/core/main/SqlMigration.java b/db-migration-core/src/main/java/org/dbmigration/core/main/SqlMigration.java new file mode 100644 index 0000000..5ecb7bb --- /dev/null +++ b/db-migration-core/src/main/java/org/dbmigration/core/main/SqlMigration.java @@ -0,0 +1,29 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.main; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +public class SqlMigration { + +} diff --git a/db-migration-core/src/main/java/org/dbmigration/core/persistence/api/DBMigrationPersistence.java b/db-migration-core/src/main/java/org/dbmigration/core/persistence/api/DBMigrationPersistence.java new file mode 100644 index 0000000..164bf73 --- /dev/null +++ b/db-migration-core/src/main/java/org/dbmigration/core/persistence/api/DBMigrationPersistence.java @@ -0,0 +1,48 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.persistence.api; + +import java.util.List; +import org.nanoboot.dbmigration.core.configuration.Configuration; +import org.nanoboot.dbmigration.core.entity.DBMigrationSchemaHistory; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +public interface DBMigrationPersistence { + public String getSqlDialect(); + public boolean doesMigrationSchemaHistoryTableExist(); + public void createMigrationSchemaHistoryTable(); + public String executeSql(String sql); + public void addMigration(DBMigrationSchemaHistory migration); + public void removeMigration(String migrationGroup, String version); + public List listMigrations(String migrationGroup); + public List listInstalledRanks(String migrationGroup); + public List listVersions(String migrationGroup); + public List listMigrationGroups(); + public DBMigrationSchemaHistory getMigrationByInstalledRank(int installedRank); + public DBMigrationSchemaHistory getMigrationByVersion(int version); + public void updateMigration(DBMigrationSchemaHistory migration); + public boolean test(); + public void setConfiguration(Configuration configurationIn); + public Configuration getConfiguration(); +} diff --git a/db-migration-core/src/main/java/org/dbmigration/core/persistence/impl/base/DBMigrationPersistenceBase.java b/db-migration-core/src/main/java/org/dbmigration/core/persistence/impl/base/DBMigrationPersistenceBase.java new file mode 100644 index 0000000..f13b285 --- /dev/null +++ b/db-migration-core/src/main/java/org/dbmigration/core/persistence/impl/base/DBMigrationPersistenceBase.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.persistence.impl.base; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.UUID; +import java.util.logging.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.nanoboot.dbmigration.core.configuration.Configuration; +import org.nanoboot.dbmigration.core.entity.DBMigrationSchemaHistory; +import org.nanoboot.dbmigration.core.main.DBMigrationException; +import org.nanoboot.dbmigration.core.main.MigrationType; +import org.nanoboot.dbmigration.core.persistence.api.DBMigrationPersistence; +import org.nanoboot.dbmigration.core.persistence.impl.sqlite.DBMigrationPersistenceSqliteImpl; +import org.nanoboot.dbmigration.core.query.DBMigrationSchemaHistoryTable; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +public abstract class DBMigrationPersistenceBase implements DBMigrationPersistence { + + private static final Logger LOG = LogManager.getLogger(DBMigrationPersistenceBase.class); + private static final String SELECT__FROM = "select * from "; + private Configuration configuration; + + @Override + public void setConfiguration(Configuration configurationIn) { + this.configuration = configurationIn; + } + + @Override + public Configuration getConfiguration() { + return configuration; + } +//https://www.sqlitetutorial.net/sqlite-java/ + + protected Connection createConnection() { + String jdbcUrl = getConfiguration().getDatasourceJdbcUrl(); + if (!getSqlDialect().equals("sqlite")) { + String user = getConfiguration().getDatasourceUser(); + String password = getConfiguration().getDatasourcePassword(); + } + Connection conn = null; + try { + //"jdbc:sqlite:C:/sqlite/db/chinook.db" + String url = jdbcUrl; + conn = DriverManager.getConnection(url); + + LOG.debug("Connection to database has been established."); + + } catch (SQLException e) { + LOG.error(e.getMessage()); + } + return conn; + } + + protected void closeConnection(Connection conn) { + try { + if (conn != null) { + conn.close(); + } + } catch (SQLException ex) { + LOG.error(ex.getMessage()); + } + } + + protected int selectOneInt(Connection conn, String sql, String columnName) { + + try ( Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql)) { + + while (rs.next()) { + return rs.getInt(columnName); + } + } catch (SQLException e) { + LOG.error(e.getMessage()); + } + final String msg = "There is no such record: " + sql; + LOG.error(msg); + throw new DBMigrationException(msg); + } + + protected String selectOneString(Connection conn, String sql, String columnName) { + + try ( Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql)) { + + while (rs.next()) { + return rs.getString(columnName); + } + } catch (SQLException e) { + LOG.error(e.getMessage()); + } + final String msg = "There is no such record: " + sql; + LOG.error(msg); + throw new DBMigrationException(msg); + } + + @Override + public boolean doesMigrationSchemaHistoryTableExist() { + return doesTableExist(createConnection(), DBMigrationSchemaHistoryTable.TABLE_NAME); + } + + public boolean doesTableExist(Connection conn, String tableName) { + String sql = SELECT__FROM + tableName; + try ( Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql)) { + return true; + } catch (SQLException e) { + LOG.error(e); + } + return false; + } + + @Override + public String executeSql(String sql) { + try ( Connection conn = createConnection();) { + conn.setAutoCommit(false); + String[] sqls = sql.split(SQL_STATEMENT_SEPARATOR); + try ( Statement stmt = conn.createStatement()) { + for (String oneSql : sqls) { + if(oneSql.isBlank()) { + continue; + } + System.err.println("Going to execute sql:\n"+oneSql); + stmt.execute(oneSql); + } + conn.commit(); + } catch (SQLException ex) { + conn.rollback(); + throw ex; + } finally { + conn.setAutoCommit(true); + } + return null; + } catch (SQLException e) { + LOG.error(e); + return e == null ? "NullPointerException may happened." : e.getMessage(); + } + } + private static final String SQL_STATEMENT_SEPARATOR = ";"; + + @Override + public void createMigrationSchemaHistoryTable() { + String result = executeSql(getCreateMigrationsTableSql()); + if (result != null) { + final String msg = "Creating table " + DBMigrationSchemaHistoryTable.TABLE_NAME + " failed: " + result; + throw new DBMigrationException(msg); + } + } + + public abstract String getCreateMigrationsTableSql(); + + @Override + public void removeMigration(String migrationGroup, String version) { + LOG.info("Going to remove migration: {},{}", migrationGroup, version); + try ( PreparedStatement preparedStatement = createPreparedStatementForRemoveMigration(createConnection(), migrationGroup, version);) { + LOG.debug("removeMigration preparedStatement.toString()::{}", preparedStatement.toString()); + boolean result = preparedStatement.execute(); + + } catch (SQLException e) { + String msg = "Deleting migration failed: " + migrationGroup + ", " + version + "\n \n" + e.getMessage(); + LOG.error(msg); + throw new DBMigrationException(msg); + } + } + + private PreparedStatement createPreparedStatementForRemoveMigration(Connection createConnection, String migrationGroup, String version) throws SQLException { + PreparedStatement preparedStatement = createConnection.prepareStatement(getDeleteMigrationPreparedSql()); + int i = 0; + preparedStatement.setString(++i, migrationGroup); + preparedStatement.setString(++i, version); + return preparedStatement; + + } + + public abstract String getDeleteMigrationPreparedSql(); + + @Override + public void addMigration(DBMigrationSchemaHistory migration) { + LOG.info(" ");; + LOG.info("* Executing next SQL migration file *");; + LOG.info("Going to add new migration to database:"); + LOG.info("{}", migration); + + try ( PreparedStatement preparedStatement = createPreparedStatementForInsertMigration(createConnection(), migration);) { + LOG.debug("addMigration preparedStatement.toString()::{}", preparedStatement.toString()); + boolean result = preparedStatement.execute(); + + } catch (SQLException e) { + String msg = "Inserting new migration failed: " + migration.toString() + "\n \n" + e.getMessage(); + LOG.error(msg); + throw new DBMigrationException(msg); + } + + } + + private PreparedStatement createPreparedStatementForInsertMigration(Connection createConnection, DBMigrationSchemaHistory migration) throws SQLException { + PreparedStatement preparedStatement = createConnection().prepareStatement(getInsertMigrationPreparedSql()); + int i = 0; + preparedStatement.setString(++i, migration.getId().toString()); + preparedStatement.setString(++i, migration.getMigrationGroup()); + preparedStatement.setInt(++i, migration.getInstalledRank()); + preparedStatement.setString(++i, migration.getVersion()); + preparedStatement.setString(++i, migration.getDescription()); + + preparedStatement.setString(++i, migration.getType().name()); + preparedStatement.setString(++i, migration.getScript()); + preparedStatement.setString(++i, migration.getHash()); + preparedStatement.setString(++i, migration.getInstalledBy()); + preparedStatement.setString(++i, migration.getInstalledOn()); + + preparedStatement.setInt(++i, migration.getExecutionTime()); + preparedStatement.setInt(++i, (migration.isSuccess() ? 1 : 0)); + return preparedStatement; + } + + public abstract String getInsertMigrationPreparedSql(); + + @Override + public List listMigrations(String migrationGroup) { + LOG.info("Listing migrations for group = {}", migrationGroup); + List list = new ArrayList<>(); + String sql = null; + try ( PreparedStatement preparedStatement = createPreparedStatementForListMigrations(createConnection(), migrationGroup); ResultSet rs = preparedStatement.executeQuery();) { + + sql = preparedStatement.toString(); + LOG.debug("listMigrations preparedStatement sql = {}", sql.toString()); + while (rs.next()) { + DBMigrationSchemaHistory migration = loadMigrationsFromResultSet(rs); + list.add(migration); + } + Collections.sort(list); + return list; + } catch (SQLException e) { + LOG.error(e); + } + final String msg = "There is no such record: " + sql; + LOG.error(msg); + throw new DBMigrationException(msg); + + } + + private DBMigrationSchemaHistory loadMigrationsFromResultSet(ResultSet rs) { + DBMigrationSchemaHistory migration = new DBMigrationSchemaHistory(); + + try { + migration.setId(UUID.fromString(rs.getString(DBMigrationSchemaHistoryTable.ID))); + migration.setMigrationGroup(rs.getString(DBMigrationSchemaHistoryTable.MIGRATION_GROUP)); + migration.setInstalledRank(rs.getInt(DBMigrationSchemaHistoryTable.INSTALLED_RANK)); + migration.setVersion(rs.getString(DBMigrationSchemaHistoryTable.VERSION)); + migration.setDescription(rs.getString(DBMigrationSchemaHistoryTable.DESCRIPTION)); + + migration.setType(MigrationType.valueOf(rs.getString(DBMigrationSchemaHistoryTable.TYPE))); + migration.setScript(rs.getString(DBMigrationSchemaHistoryTable.SCRIPT)); + migration.setHash(rs.getString(DBMigrationSchemaHistoryTable.HASH)); + migration.setInstalledBy(rs.getString(DBMigrationSchemaHistoryTable.INSTALLED_BY)); + migration.setInstalledOn(rs.getString(DBMigrationSchemaHistoryTable.INSTALLED_ON)); + + migration.setExecutionTime(rs.getInt(DBMigrationSchemaHistoryTable.EXECUTION_TIME)); + migration.setSuccess(rs.getInt(DBMigrationSchemaHistoryTable.SUCCESS) != 0); + + return migration; + } catch (SQLException ex) { + java.util.logging.Logger.getLogger(DBMigrationPersistenceSqliteImpl.class.getName()).log(Level.SEVERE, null, ex); + throw new DBMigrationException(ex); + } + + } + + private PreparedStatement createPreparedStatementForListMigrations(Connection createConnection, String migrationGroup) throws SQLException { + PreparedStatement preparedStatement = createConnection.prepareStatement(getListMigrationsPreparedSql()); + preparedStatement.setString(1, migrationGroup); + return preparedStatement; + } + + public abstract String getListMigrationsPreparedSql(); +} diff --git a/db-migration-core/src/main/java/org/dbmigration/core/persistence/impl/sqlite/DBMigrationPersistenceSqliteImpl.java b/db-migration-core/src/main/java/org/dbmigration/core/persistence/impl/sqlite/DBMigrationPersistenceSqliteImpl.java new file mode 100644 index 0000000..57f67c2 --- /dev/null +++ b/db-migration-core/src/main/java/org/dbmigration/core/persistence/impl/sqlite/DBMigrationPersistenceSqliteImpl.java @@ -0,0 +1,140 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.persistence.impl.sqlite; + +import java.sql.Connection; +import java.util.List; +import org.apache.logging.log4j.LogManager; +import org.nanoboot.dbmigration.core.entity.DBMigrationSchemaHistory; +import org.nanoboot.dbmigration.core.persistence.impl.base.DBMigrationPersistenceBase; +import org.nanoboot.dbmigration.core.query.DBMigrationSchemaHistoryTable; +import org.nanoboot.dbmigration.core.persistence.api.DBMigrationPersistence; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +public class DBMigrationPersistenceSqliteImpl extends DBMigrationPersistenceBase implements DBMigrationPersistence { + + private static final org.apache.logging.log4j.Logger LOG = LogManager.getLogger(DBMigrationPersistenceSqliteImpl.class); + private static final String SQLITE = "sqlite"; + private static final String SQL_CREATE_TABLE_DB_MIGRATION_SCHEMA_HISTORY + = """ + CREATE TABLE "DB_MIGRATION_SCHEMA_HISTORY" ( + "ID" TEXT NOT NULL, + "MIGRATION_GROUP" TEXT NOT NULL, + "INSTALLED_RANK" INTEGER NOT NULL, + "VERSION" TEXT NOT NULL, + "DESCRIPTION" TEXT NOT NULL, + "TYPE" TEXT NOT NULL, + "SCRIPT" TEXT NOT NULL, + "HASH" TEXT NOT NULL UNIQUE, + "INSTALLED_BY" TEXT NOT NULL, + "INSTALLED_ON" TEXT NOT NULL, + "EXECUTION_TIME" INTEGER NOT NULL, + "SUCCESS" INTEGER NOT NULL, + PRIMARY KEY("ID"), + CONSTRAINT "DB_MIGRATION_SCHEMA_HISTORY_UNIQUE_CONSTRAINT_MIGRATION_GROUP_AND_INSTALLED_RANK" UNIQUE("MIGRATION_GROUP","INSTALLED_RANK"), + CONSTRAINT "DB_MIGRATION_SCHEMA_HISTORY_UNIQUE_CONSTRAINT_MIGRATION_GROUP_AND_VERSION" UNIQUE("MIGRATION_GROUP","VERSION") + ); + """; + private static final String SQL_LIST_MIGRATIONS + = "SELECT * FROM " + DBMigrationSchemaHistoryTable.TABLE_NAME + + " WHERE " + DBMigrationSchemaHistoryTable.MIGRATION_GROUP + + " = ? ORDER BY " + DBMigrationSchemaHistoryTable.VERSION; + private static final String SQL_INSERT_MIGRATION + = "INSERT INTO " + DBMigrationSchemaHistoryTable.TABLE_NAME + + " VALUES (?,?,?,?,?,?,?,?,?,?,?,?)"; + + private static final String SQL_DELETE_MIGRATION + = "DELETE FROM " + DBMigrationSchemaHistoryTable.TABLE_NAME + + " WHERE " + DBMigrationSchemaHistoryTable.MIGRATION_GROUP + " = ? AND " + + DBMigrationSchemaHistoryTable.VERSION + " = ? "; + + @Override + public String getSqlDialect() { + return SQLITE; + } + + @Override + public List listInstalledRanks(String migrationGroup) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public List listVersions(String migrationGroup) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public DBMigrationSchemaHistory getMigrationByInstalledRank(int installedRank) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public DBMigrationSchemaHistory getMigrationByVersion(int installedRank) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void updateMigration(DBMigrationSchemaHistory migration) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean test() { + Connection conn = createConnection(); + int testResult = selectOneInt(conn, SELECT_1__2_AS_ONE_PLUS_TWO_IS, "ONE_PLUS_TWO_IS"); + LOG.info("Test: " + SELECT_1__2_AS_ONE_PLUS_TWO_IS + " returned: " + testResult); + LOG.info("doesTableExist(TEST_TABLE)=" + doesTableExist(conn, "TEST_TABLE")); + LOG.info("doesTableExist(DB_MIGRATION_SCHEMA_HISTORY)=" + doesTableExist(conn, "DB_MIGRATION_SCHEMA_HISTORY")); + LOG.info("doesTableExist(DB_MIGRATION_SCHEMA_HISTORY2)=" + doesTableExist(conn, "DB_MIGRATION_SCHEMA_HISTORY2")); + closeConnection(conn); + return true; + } + private static final String SELECT_1__2_AS_ONE_PLUS_TWO_IS = "select (1 + 2) as ONE_PLUS_TWO_IS"; + + @Override + public List listMigrationGroups() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public String getCreateMigrationsTableSql() { + return SQL_CREATE_TABLE_DB_MIGRATION_SCHEMA_HISTORY; + } + + @Override + public String getDeleteMigrationPreparedSql() { + return SQL_DELETE_MIGRATION; + } + + @Override + public String getInsertMigrationPreparedSql() { + return SQL_INSERT_MIGRATION; + } + + @Override + public String getListMigrationsPreparedSql() { + return SQL_LIST_MIGRATIONS; + } + +} diff --git a/db-migration-core/src/main/java/org/dbmigration/core/query/DBMigrationSchemaHistoryTable.java b/db-migration-core/src/main/java/org/dbmigration/core/query/DBMigrationSchemaHistoryTable.java new file mode 100644 index 0000000..36cca58 --- /dev/null +++ b/db-migration-core/src/main/java/org/dbmigration/core/query/DBMigrationSchemaHistoryTable.java @@ -0,0 +1,50 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.query; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +public class DBMigrationSchemaHistoryTable { + + public DBMigrationSchemaHistoryTable() { + //No instantiation needed. + } + + public static final String TABLE_NAME = "DB_MIGRATION_SCHEMA_HISTORY"; + + public static final String ID = "ID"; + public static final String MIGRATION_GROUP = "MIGRATION_GROUP"; + public static final String INSTALLED_RANK = "INSTALLED_RANK"; + public static final String VERSION = "VERSION"; + public static final String DESCRIPTION = "DESCRIPTION"; + + public static final String TYPE = "TYPE"; + public static final String SCRIPT = "SCRIPT"; + public static final String HASH = "HASH"; + public static final String INSTALLED_BY = "INSTALLED_BY"; + public static final String INSTALLED_ON = "INSTALLED_ON"; + + public static final String EXECUTION_TIME = "EXECUTION_TIME"; + public static final String SUCCESS = "SUCCESS"; + +} diff --git a/db-migration-core/src/main/java/org/dbmigration/core/resources/FileSystemSqlFileProvider.java b/db-migration-core/src/main/java/org/dbmigration/core/resources/FileSystemSqlFileProvider.java new file mode 100644 index 0000000..75841c0 --- /dev/null +++ b/db-migration-core/src/main/java/org/dbmigration/core/resources/FileSystemSqlFileProvider.java @@ -0,0 +1,58 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.resources; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.nanoboot.dbmigration.core.main.DBMigrationException; +import static org.nanoboot.dbmigration.core.utils.DBMigrationUtils.readTextFromFile; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +public final class FileSystemSqlFileProvider implements SqlFileProvider { + + private static final Logger LOG = LogManager.getLogger(FileSystemSqlFileProvider.class); + @Override + public List provide(String path, Class clazz) { + return loadSqlFilesFromPath(path); + } + + private List loadSqlFilesFromPath(String sqlMigrationsDirectory) { + List sqlFiles = new ArrayList<>(); + for (File f : new File(sqlMigrationsDirectory).listFiles()) { + if (f.isDirectory()) { + final String msg = "File \"" + f.getAbsolutePath() + "\" is directory, sqlMigrationsDirectory cannot contain any directory."; + LOG.error(msg); + throw new DBMigrationException(msg); + } + + SqlFile sqlFile = new SqlFile(f.getName(), readTextFromFile(f.getAbsolutePath())); + sqlFiles.add(sqlFile); + } + return sqlFiles; + } + +} diff --git a/db-migration-core/src/main/java/org/dbmigration/core/resources/ResourcesSqlFileProvider.java b/db-migration-core/src/main/java/org/dbmigration/core/resources/ResourcesSqlFileProvider.java new file mode 100644 index 0000000..e41fe5b --- /dev/null +++ b/db-migration-core/src/main/java/org/dbmigration/core/resources/ResourcesSqlFileProvider.java @@ -0,0 +1,149 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.resources; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Stream; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.nanoboot.dbmigration.core.main.DBMigrationException; +import org.nanoboot.dbmigration.core.utils.DBMigrationConstants; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +public final class ResourcesSqlFileProvider implements SqlFileProvider { +private static final Logger LOG = LogManager.getLogger(ResourcesSqlFileProvider.class); + public static String createPath(String sqlDialect, String nameOfMigrations) { + return DBMigrationConstants.RESOURCES_ROOT_DIRECTORY_NAME + File.separator + sqlDialect + File.separator + nameOfMigrations; + } + + @Override + public List provide(String path) { + throw new UnsupportedOperationException(); + } + + @Override + public List provide(String path, Class clazz) { + return loadSqlFilesFromJarResources(path, clazz); + } + + private List loadSqlFilesFromJarResources(String path, Class clazz) { + try { + return loadSqlFilesFromJarResourcesWithIOException(path, clazz); + } catch (IOException ex) { + LOG.error("Loading sql files from jar failed:",ex); + throw new DBMigrationException(ex); + } + } + + private static List loadSqlFilesFromJarResourcesWithIOException(String p, Class clazz) throws IOException { + List result = new ArrayList<>(); + try { + List paths = getPathsFromResourceJar(p, clazz); + for (Path path : paths) { + LOG.debug("Path : {}", path); + + String filePathInJAR = path.toString(); + + if (filePathInJAR.startsWith("/")) { + filePathInJAR = filePathInJAR.substring(1, filePathInJAR.length()); + } + + LOG.debug("filePathInJAR : {}", filePathInJAR); + InputStream is = getFileFromResourceAsStream(filePathInJAR, clazz); + String text = loadTextFromInputStream(is); + SqlFile sf = new SqlFile(path.getFileName().toString(), text); + result.add(sf); + } + + } catch (URISyntaxException | IOException e) { + LOG.error(e); + throw new DBMigrationException(e); + } + return result; + } + + private static InputStream getFileFromResourceAsStream(String fileName, Class clazz) { + ClassLoader classLoader = clazz.getClassLoader(); + InputStream inputStream = classLoader.getResourceAsStream(fileName); + if (inputStream == null) { + LOG.error("File not found! {}",fileName); + throw new IllegalArgumentException("File not found! " + fileName); + } else { + return inputStream; + } + + } + + private static List getPathsFromResourceJar(String folder, Class clazz) + throws URISyntaxException, IOException { + List result; + + String jarPath = clazz.getProtectionDomain() + .getCodeSource() + .getLocation() + .toURI() + .getPath(); + LOG.debug("JAR Path :{}",jarPath); + + URI uri = URI.create("jar:file:" + jarPath); + try ( FileSystem fs = FileSystems.newFileSystem(uri, Collections.emptyMap());Stream stream = Files.walk(fs.getPath(folder))) { + result = stream + .filter(Files::isRegularFile) + .toList(); + } + + return result; + + } + + private static String loadTextFromInputStream(InputStream is) { + StringBuilder sb = new StringBuilder(); + try ( InputStreamReader streamReader = new InputStreamReader(is, StandardCharsets.UTF_8); BufferedReader reader = new BufferedReader(streamReader)) { + + String line; + while ((line = reader.readLine()) != null) { + sb.append(line); + sb.append("\n"); + } + + } catch (IOException e) { + e.printStackTrace(); + } + return sb.toString(); + } +} diff --git a/db-migration-core/src/main/java/org/dbmigration/core/resources/SqlFile.java b/db-migration-core/src/main/java/org/dbmigration/core/resources/SqlFile.java new file mode 100644 index 0000000..2372e5e --- /dev/null +++ b/db-migration-core/src/main/java/org/dbmigration/core/resources/SqlFile.java @@ -0,0 +1,51 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.resources; + +import lombok.Data; +import org.nanoboot.dbmigration.core.utils.DBMigrationUtils; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +@Data +public class SqlFile implements Comparable { + + private SqlFileName sqlFileName; + private String fileName; + private String content; + + public SqlFile(String fileName, String content) { + this.fileName = fileName; + this.content = content; + this.sqlFileName = new SqlFileName(fileName); + } + + public String calculateHash() { + return DBMigrationUtils.hashSha1(content); + } + + @Override + public int compareTo(SqlFile o) { + return this.getSqlFileName().compareTo(o.getSqlFileName()); + } +} diff --git a/db-migration-core/src/main/java/org/dbmigration/core/resources/SqlFileName.java b/db-migration-core/src/main/java/org/dbmigration/core/resources/SqlFileName.java new file mode 100644 index 0000000..28d5737 --- /dev/null +++ b/db-migration-core/src/main/java/org/dbmigration/core/resources/SqlFileName.java @@ -0,0 +1,107 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.resources; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.nanoboot.dbmigration.core.main.DBMigrationException; +import org.nanoboot.dbmigration.core.utils.DBMigrationUtils; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +@EqualsAndHashCode +@ToString +public class SqlFileName implements Comparable { + + private static final Logger LOG = LogManager.getLogger(SqlFileName.class); + + private static final String FILE = "File "; + + @Getter + private final String fileName; + @Getter + private final String version; + @Getter + private final String description; + private final SqlFileVersion sqlFileVersion; + + public SqlFileName(String fileNameIn) { + this.fileName = fileNameIn; + if (!fileName.endsWith(".sql")) { + final String msg = FILE + fileName + " does not end with \".sql\"."; + throw new DBMigrationException(msg); + } + //Example: V2_1__First_Changes.sql + String tmpFileName = fileName.replace(".sql", ""); + //Example: V2_1__First_Changes + if (!fileName.startsWith("V")) { + final String msg = FILE + fileName + " does not start with \"V\"."; + throw new DBMigrationException(msg); + } + if (!fileName.contains("__")) { + final String msg = FILE + fileName + " does not contain \"__\"."; + throw new DBMigrationException(msg); + } + tmpFileName = tmpFileName.substring(1); + //Example: 2_1__First_Changes + String[] array = tmpFileName.split("__"); + + String tmpVersion = array[0]; + String[] tmpVersionArray = tmpVersion.split("_"); + StringBuilder tmpVersionStringBuilder = new StringBuilder(); + for (int i = 0; i < tmpVersionArray.length; i++) { + String subVersion = tmpVersionArray[i]; + tmpVersionStringBuilder.append(Integer.valueOf(subVersion)); + boolean lastIndex = i == (tmpVersionArray.length - 1); + if (!lastIndex) { + tmpVersionStringBuilder.append("."); + } + } + String tmpDescription = array[1]; + this.version = tmpVersionStringBuilder.toString(); + this.description = tmpDescription.replace("_", " "); + this.sqlFileVersion = new SqlFileVersion(this.version); + } + + @Override + public int compareTo(SqlFileName o) { + int result = this.sqlFileVersion.compareTo(o.sqlFileVersion); + + if (result == 0 && !this.getFileName().equals(o.getFileName())) { + String msg = DBMigrationUtils + .formatString( + "Cannot compare instances of SqlFileName with same version and different file names: {}, {}", + this.toString(), + o.toString() + ); + LOG.error(msg); + throw new DBMigrationException(msg); + + } + return result; + } + +} diff --git a/db-migration-core/src/main/java/org/dbmigration/core/resources/SqlFileProvider.java b/db-migration-core/src/main/java/org/dbmigration/core/resources/SqlFileProvider.java new file mode 100644 index 0000000..c9ca228 --- /dev/null +++ b/db-migration-core/src/main/java/org/dbmigration/core/resources/SqlFileProvider.java @@ -0,0 +1,37 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.resources; + +import java.util.List; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +public interface SqlFileProvider { + + List provide(String path, Class clazz); + + default List provide(String path) { + return provide(path, null); + } + +} diff --git a/db-migration-core/src/main/java/org/dbmigration/core/resources/SqlFileVersion.java b/db-migration-core/src/main/java/org/dbmigration/core/resources/SqlFileVersion.java new file mode 100644 index 0000000..888ef88 --- /dev/null +++ b/db-migration-core/src/main/java/org/dbmigration/core/resources/SqlFileVersion.java @@ -0,0 +1,82 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.resources; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +@EqualsAndHashCode +public class SqlFileVersion implements Comparable { + + private static final Logger LOG = LogManager.getLogger(SqlFileVersion.class); + @Getter + private final String version; + + private final int[] subversions; + + public SqlFileVersion(String version) { + this.version = version; + String[] versionArray = version.split("\\."); + subversions = new int[versionArray.length]; + for (int i = 0; i < versionArray.length; i++) { + subversions[i] = Integer.valueOf(versionArray[i]); + } + } + + private int getSubversion(int index) { + if (index >= subversions.length) { + return 0; + } + return this.subversions[index]; + } + + private int getSubversionsCount() { + return subversions.length; + } + + @Override + public int compareTo(SqlFileVersion o) { + int maxSubVersionCount = Math.max(this.getSubversionsCount(), o.getSubversionsCount()); + int result = 0; + + LOG.trace("this.version={}", this.version); + LOG.trace("o.version={}", o.version); + for (int i = 0; i < maxSubVersionCount; i++) { + Integer i1 = this.getSubversion(i); + Integer i2 = o.getSubversion(i); + LOG.trace("this.getSubversion({})=", i1); + LOG.trace("o.getSubversion({})=", i2); + int tempResult = i1.compareTo(i2); + if (tempResult != 0) { + result = tempResult; + break; + } + } + return result; + } + +} diff --git a/db-migration-core/src/main/java/org/dbmigration/core/utils/DBMigrationConstants.java b/db-migration-core/src/main/java/org/dbmigration/core/utils/DBMigrationConstants.java new file mode 100644 index 0000000..f01c785 --- /dev/null +++ b/db-migration-core/src/main/java/org/dbmigration/core/utils/DBMigrationConstants.java @@ -0,0 +1,34 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.utils; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +public class DBMigrationConstants { + public static final String RESOURCES_ROOT_DIRECTORY_NAME = "db_migrations"; + + private DBMigrationConstants() { + //No instantiation needed. + } + +} diff --git a/db-migration-core/src/main/java/org/dbmigration/core/utils/DBMigrationUtils.java b/db-migration-core/src/main/java/org/dbmigration/core/utils/DBMigrationUtils.java new file mode 100644 index 0000000..e5ea077 --- /dev/null +++ b/db-migration-core/src/main/java/org/dbmigration/core/utils/DBMigrationUtils.java @@ -0,0 +1,88 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.utils; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import org.nanoboot.powerframework.security.hash.locator.HashCalculatorLocator; +import java.security.NoSuchAlgorithmException; +import org.nanoboot.dbmigration.core.main.DBMigrationException; +import org.nanoboot.powerframework.security.hash.locator.HashImpl; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +public class DBMigrationUtils { + + private DBMigrationUtils() { + throw new java.lang.UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } + private static final String STRING_FORMATTING_PLACE_HOLDER = "{}"; + + /** + * + * @param password + * @return hash, in case of failure :: and the String representation of that + * thrown exception + * @throws NoSuchAlgorithmException + * @throws UnsupportedEncodingException + */ + public static String hashSha1(String password) { + return HashCalculatorLocator.locate(HashImpl.SHA_1).hash(password); + } + + public static String formatString(String string, Object... args) { + return String.format(string.replace(STRING_FORMATTING_PLACE_HOLDER, STRING_FORMATTING_PLACE_HOLDER2), args); + } + private static final String STRING_FORMATTING_PLACE_HOLDER2 = "%s"; + + //TODO move to Power Framework + public static void writeToFile(String path, String text) { + try ( BufferedWriter writer = new BufferedWriter(new FileWriter(path))) { + writer.write(text); + } catch (IOException e) { + throw new DBMigrationException(e); + } + } + //TODO move to Power Framework + public static String readTextFromFile(String path) { + try { + try (BufferedReader br = new BufferedReader(new FileReader(path))) { + StringBuilder sb = new StringBuilder(); + String line = br.readLine(); + + while (line != null) { + sb.append(line); + sb.append(System.lineSeparator()); + line = br.readLine(); + } + return sb.toString(); + } + } catch (IOException e) { + throw new DBMigrationException(e); + } + } +} diff --git a/db-migration-core/src/main/resources/log4j2-example.xml b/db-migration-core/src/main/resources/log4j2-example.xml new file mode 100644 index 0000000..3b3c067 --- /dev/null +++ b/db-migration-core/src/main/resources/log4j2-example.xml @@ -0,0 +1,28 @@ + + + + dbm.log + + + + + + + + + + + + + + + + + + + diff --git a/db-migration-core/src/main/resources/log4j2.xml b/db-migration-core/src/main/resources/log4j2.xml new file mode 100644 index 0000000..a1873c0 --- /dev/null +++ b/db-migration-core/src/main/resources/log4j2.xml @@ -0,0 +1,28 @@ + + + + /rv/data/desktop/development/logs/dbm/dbm.log + + + + + + + + + + + + + + + + + + + diff --git a/db-migration-core/src/test/java/org/nanoboot/dbmigration/configuration/ConfigurationEntryTest.java b/db-migration-core/src/test/java/org/nanoboot/dbmigration/configuration/ConfigurationEntryTest.java new file mode 100644 index 0000000..c05cce3 --- /dev/null +++ b/db-migration-core/src/test/java/org/nanoboot/dbmigration/configuration/ConfigurationEntryTest.java @@ -0,0 +1,100 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.configuration; + +import org.nanoboot.dbmigration.core.main.DBMigrationException; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +public class ConfigurationEntryTest { + + public ConfigurationEntryTest() { + } + + @BeforeAll + public static void setUpClass() { + } + + @AfterAll + public static void tearDownClass() { + } + + @BeforeEach + public void setUp() { + } + + @AfterEach + public void tearDown() { + } + + /** + * Test of ofArgument method, of class ConfigurationEntry. + */ + @Test + public void testOfArgument() { + System.out.println("ofArgument"); + //prepare + String arg = "name=Johnny"; + //execute + //assert + Throwable exception = assertThrows(DBMigrationException.class, () -> ConfigurationEntry.ofArgument(arg)); + assertEquals("Arguments must start with - since second position: " + arg, exception.getMessage()); + } + /** + * Test of ofArgument method, of class ConfigurationEntry. + */ + @Test + public void testOfArgument2() { + System.out.println("ofArgument 2"); + //prepare + String arg = "-nameJohnny"; + //execute + //assert + Throwable exception = assertThrows(DBMigrationException.class, () -> ConfigurationEntry.ofArgument(arg)); + assertEquals("Array is " + "1"+ ", but 2 was expected.", exception.getMessage()); + } + /** + * Test of ofArgument method, of class ConfigurationEntry. + */ + @Test + public void testOfArgument3() { + System.out.println("ofArgument 3"); + //prepare + String arg = "-name=Johnny"; + String keyExpected = "name"; + String valueExpected = "Johnny"; + //execute + ConfigurationEntry ce = ConfigurationEntry.ofArgument(arg); + //assert + assertEquals(keyExpected, ce.getKey()); + assertEquals(valueExpected, ce.getValue()); + } + + +} diff --git a/db-migration-core/src/test/java/org/nanoboot/dbmigration/configuration/ConfigurationTest.java b/db-migration-core/src/test/java/org/nanoboot/dbmigration/configuration/ConfigurationTest.java new file mode 100644 index 0000000..5803976 --- /dev/null +++ b/db-migration-core/src/test/java/org/nanoboot/dbmigration/configuration/ConfigurationTest.java @@ -0,0 +1,637 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.configuration; + +import java.util.ArrayList; +import java.util.List; +import org.nanoboot.dbmigration.core.main.DBMigrationException; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +public class ConfigurationTest { + + public ConfigurationTest() { + } + + @BeforeAll + public static void setUpClass() { + } + + @AfterAll + public static void tearDownClass() { + } + + @BeforeEach + public void setUp() { + } + + @AfterEach + public void tearDown() { + } + + /** + * Test of add method, of class Configuration. + */ + @Test + public void testAdd_ConfigurationEntry() { + System.out.println("testAdd_ConfigurationEntry"); + //prepare + ConfigurationEntry ce = new ConfigurationEntry("dbmigration.a", "p"); + Configuration conf = new Configuration(); + //execute + conf.add(ce); + //assert + assertTrue(conf.has("dbmigration.a")); + assertEquals("p", conf.get("dbmigration.a")); + } + + /** + * Test of add method, of class Configuration. + */ + @Test + public void testAdd_ConfigurationEntry2() { + System.out.println("testAdd_ConfigurationEntry2"); + //prepare + ConfigurationEntry ce = new ConfigurationEntry("a", "p"); + Configuration conf = new Configuration(); + //execute + Throwable exception = assertThrows(DBMigrationException.class, () -> conf.add(ce)); + assertEquals("Key does not start with prefix dbmigration.", exception.getMessage()); + //assert + } + + /** + * Test of add method, of class Configuration. + */ + @Test + public void testAdd_String_String() { + System.out.println("testAdd_String_String"); + //prepare + Configuration conf = new Configuration(); + //execute + conf.add("dbmigration.a", "p"); + //assert + assertTrue(conf.has("dbmigration.a")); + assertEquals("p", conf.get("dbmigration.a")); + } + + /** + * Test of add method, of class Configuration. + */ + @Test + public void testAdd_String_String2() { + System.out.println("testAdd_String_String2"); + //prepare + Configuration conf = new Configuration(); + //execute + Throwable exception = assertThrows(DBMigrationException.class, () -> conf.add("a", "p")); + assertEquals("Key does not start with prefix dbmigration.", exception.getMessage()); + // + conf.add("dbmigration.kkk", null); + assertEquals(false, conf.has("dbmigration.kkk")); + //assert + } + + /** + * Test of get method, of class Configuration. + */ + @Test + public void testGet() { + System.out.println("testGet"); + //prepare + Configuration conf = new Configuration(); + //execute + conf.add("dbmigration.a", "p"); + //assert + assertEquals("p", conf.get("dbmigration.a")); + // + Throwable exception = assertThrows(DBMigrationException.class, () -> conf.get("dbmigration.b")); + assertEquals("There is no key: dbmigration.b", exception.getMessage()); + } + + /** + * Test of getMandatory method, of class Configuration. + */ + @Test + public void testGetMandatory() { + System.out.println("testGetMandatory"); + //prepare + Configuration conf = new Configuration(); + //execute + conf.add("dbmigration.a", "p"); + //assert + assertEquals("p", conf.getMandatory("dbmigration.a")); + // + Throwable exception = assertThrows(DBMigrationException.class, () -> conf.getMandatory("dbmigration.b")); + assertEquals("There is no key: dbmigration.b", exception.getMessage()); + } + + /** + * Test of getOptional method, of class Configuration. + */ + @Test + public void testGetOptional() { + System.out.println("testGetOptional"); + //prepare + Configuration conf = new Configuration(); + //execute + conf.add("dbmigration.a", "p"); + //assert + assertEquals("p", conf.getOptional("dbmigration.a")); + assertNull(conf.getOptional("dbmigration.z")); + + } + + /** + * Test of has method, of class Configuration. + */ + @Test + public void testHas() { + System.out.println("has"); + //prepare + String key = "dbmigration.e"; + Configuration instance = new Configuration(); + //execute + instance.add("dbmigration.e", "f"); + boolean expResult = true; + boolean result = instance.has(key); + assertEquals(expResult, result); + Throwable exception = assertThrows(DBMigrationException.class, () -> instance.has("e")); + assertEquals("Key does not start with prefix dbmigration.", exception.getMessage()); + assertEquals(false, instance.has("dbmigration.k")); + } + + /** + * Test of remove method, of class Configuration. + */ + @Test + public void testRemove() { + System.out.println("testRemove"); + //prepare + Configuration instance = new Configuration(); + //execute + assertEquals(false, instance.has("dbmigration.e")); + instance.add("dbmigration.e", "f"); + assertEquals(true, instance.has("dbmigration.e")); + instance.remove("dbmigration.e"); + assertEquals(false, instance.has("dbmigration.e")); + } + + /** + * Test of listKeys method, of class Configuration. + */ + @Test + public void testListKeys() { + System.out.println("testListKeys"); + //prepare + Configuration instance = new Configuration(); + //execute + instance.add("dbmigration.a", "b"); + instance.add("dbmigration.c", "d"); + instance.add("dbmigration.k", "l"); + instance.add("dbmigration.m", "n"); + List result = instance.listKeys(); + //assert + assertEquals(4, result.size()); + assertEquals(true, result.contains("dbmigration.a")); + assertEquals(true, result.contains("dbmigration.c")); + assertEquals(true, result.contains("dbmigration.k")); + assertEquals(true, result.contains("dbmigration.m")); + assertEquals(false, result.contains("dbmigration.o")); + } + + /** + * Test of list method, of class Configuration. + */ + @Test + public void testList() { + System.out.println("testListKeys"); + //prepare + Configuration instance = new Configuration(); + String expectedResult = "a-b--c-d--k-l--m-n--"; + StringBuilder sb = new StringBuilder(); + //execute + instance.add("dbmigration.a", "b"); + instance.add("dbmigration.c", "d"); + instance.add("dbmigration.k", "l"); + instance.add("dbmigration.m", "n"); + List result = instance.list(); + List list2 = new ArrayList<>(); + for (ConfigurationEntry ce : result) { + list2.add(ce.getKey() + "_" + ce.getValue()); + } + //assert + assertEquals(4, result.size()); + assertEquals(true, list2.contains("dbmigration.a_b")); + assertEquals(true, list2.contains("dbmigration.c_d")); + assertEquals(true, list2.contains("dbmigration.k_l")); + assertEquals(true, list2.contains("dbmigration.m_n")); + assertEquals(false, list2.contains("dbmigration.o_p")); + } + + /** + * Test of getDatasourceJdbcUrl method, of class Configuration. + */ + @Test + public void testGetDatasourceJdbcUrl() { + System.out.println("testGetDatasourceJdbcUrl"); + //prepare + Configuration instance = new Configuration(); + String expectedResult = "test"; + //execute + instance.add(ConfigurationKeys.DATASOURCE_JDBC_URL, "test"); + //assert + assertEquals("test", instance.getDatasourceJdbcUrl()); + } + + /** + * Test of setDatasourceJdbcUrl method, of class Configuration. + */ + @Test + public void testSetDatasourceJdbcUrl() { + System.out.println("testGetDatasourceJdbcUrl"); + //prepare + Configuration instance = new Configuration(); + String expectedResult = "test"; + //execute + instance.setDatasourceJdbcUrl("test"); + //assert + assertEquals(expectedResult, instance.get(ConfigurationKeys.DATASOURCE_JDBC_URL)); + } + + /** + * Test of getDatasourceUser method, of class Configuration. + */ + @Test + public void testGetDatasourceUser() { + System.out.println("testGetDatasourceUser"); + //prepare + Configuration instance = new Configuration(); + String expectedResult = "test"; + //execute + instance.add(ConfigurationKeys.DATASOURCE_USER, "test"); + //assert + assertEquals(expectedResult, instance.getDatasourceUser()); + } + + /** + * Test of setDatasourceUuser method, of class Configuration. + */ + @Test + public void testSetDatasourceUser() { + System.out.println("testGetDatasourceJdbcUrl"); + //prepare + Configuration instance = new Configuration(); + String expectedResult = "test"; + //execute + instance.setDatasourceUser("test"); + //assert + assertEquals(expectedResult, instance.get(ConfigurationKeys.DATASOURCE_USER)); + } + + /** + * Test of getDatasourcePassword method, of class Configuration. + */ + @Test + public void testGetDatasourcePassword() { + System.out.println("testGetDatasourcePassword"); + //prepare + Configuration instance = new Configuration(); + String expectedResult = "test"; + //execute + instance.add(ConfigurationKeys.DATASOURCE_PASSWORD, "test"); + //assert + assertEquals(expectedResult, instance.getDatasourcePassword()); + } + + /** + * Test of setDatasourcePassword method, of class Configuration. + */ + @Test + public void testSetDatasourcePassword() { + System.out.println("testSetDatasourcePassword"); + //prepare + Configuration instance = new Configuration(); + String expectedResult = "test"; + //execute + instance.setDatasourcePassword("test"); + //assert + assertEquals(expectedResult, instance.get(ConfigurationKeys.DATASOURCE_PASSWORD)); + } + + /** + * Test of getName method, of class Configuration. + */ + @Test + public void testGetName() { + System.out.println("testGetName"); + //prepare + Configuration instance = new Configuration(); + String expectedResult = "test"; + //execute + instance.add(ConfigurationKeys.NAME, "test"); + //assert + assertEquals(expectedResult, instance.getName()); + } + + /** + * Test of setName method, of class Configuration. + */ + @Test + public void testSetName() { + System.out.println("testSetName"); + //prepare + Configuration instance = new Configuration(); + String expectedResult = "test"; + //execute + instance.setName("test"); + //assert + assertEquals(expectedResult, instance.get(ConfigurationKeys.NAME)); + } + + /** + * Test of getSqlDialect method, of class Configuration. + */ + @Test + public void testGetSqlDialect() { + System.out.println("testGetSqlDialect"); + //prepare + Configuration instance = new Configuration(); + String expectedResult = "test"; + //execute + instance.add(ConfigurationKeys.SQL_DIALECT, "test"); + //assert + assertEquals(expectedResult, instance.getSqlDialect()); + } + + /** + * Test of setSqlDialect method, of class Configuration. + */ + @Test + public void testSetSqlDialect() { + System.out.println("testSetSqlDialect"); + //prepare + Configuration instance = new Configuration(); + String expectedResult = "test"; + //execute + instance.setSqlDialect("test"); + //assert + assertEquals(expectedResult, instance.get(ConfigurationKeys.SQL_DIALECT)); + } + + /** + * Test of getSqlDialectImplClass method, of class Configuration. + */ + @Test + public void testGetSqlDialectImplClass() { + System.out.println("testGetSqlDialectImplClass"); + //prepare + Configuration instance = new Configuration(); + String expectedResult = "test"; + //execute + instance.add(ConfigurationKeys.SQL_DIALECT_IMPL_CLASS, "test"); + //assert + assertEquals(expectedResult, instance.getSqlDialectImplClass()); + } + + /** + * Test of setSqlDialectImplClass method, of class Configuration. + */ + @Test + public void testSetSqlDialectImplClass() { + System.out.println("testSetSqlDialectImplClass"); + //prepare + Configuration instance = new Configuration(); + String expectedResult = "test"; + //execute + instance.setSqlDialectImplClass("test"); + //assert + assertEquals(expectedResult, instance.get(ConfigurationKeys.SQL_DIALECT_IMPL_CLASS)); + } + + /** + * Test of getSqlMigrationsDirectory method, of class Configuration. + */ + @Test + public void testGetSqlMigrationsDirectory() { + System.out.println("testGetSqlMigrationsDirectory"); + //prepare + Configuration instance = new Configuration(); + String expectedResult = "test"; + //execute + instance.add(ConfigurationKeys.SQL_MIGRATIONS_DIRECTORY, "test"); + //assert + assertEquals(expectedResult, instance.getSqlMigrationsDirectory()); + } + + /** + * Test of setSqlMigrationsDirectory method, of class Configuration. + */ + @Test + public void testSetSqlMigrationsDirectory() { + System.out.println("testSetSqlMigrationsDirectory"); + //prepare + Configuration instance = new Configuration(); + String expectedResult = "test"; + //execute + instance.setSqlMigrationsDirectory("test"); + //assert + assertEquals(expectedResult, instance.get(ConfigurationKeys.SQL_MIGRATIONS_DIRECTORY)); + } + /** + * Test of getSqlMigrationsDirectory method, of class Configuration. + */ + @Test + public void testGetSqlMigrationsClass() { + System.out.println("testGetSqlMigrationsClass"); + //prepare + Configuration instance = new Configuration(); + String expectedResult = "com.johnny.asuperapp.ASuperAppMain"; + //execute + instance.add(ConfigurationKeys.SQL_MIGRATIONS_CLASS, "com.johnny.asuperapp.ASuperAppMain"); + //assert + assertEquals(expectedResult, instance.getSqlMigrationsClass()); + } + + /** + * Test of setSqlMigrationsDirectory method, of class Configuration. + */ + @Test + public void testSetSqlMigrationsClass() { + System.out.println("testSetSqlMigrationsClass"); + //prepare + Configuration instance = new Configuration(); + String expectedResult = "com.johnny.asuperapp.ASuperAppMain"; + //execute + instance.setSqlMigrationsClass("com.johnny.asuperapp.ASuperAppMain"); + //assert + assertEquals(expectedResult, instance.get(ConfigurationKeys.SQL_MIGRATIONS_CLASS)); + } + /** + * Test of getInstalledBy method, of class Configuration. + */ + @Test + public void testGetInstalledBy() { + System.out.println("testGetInstalledBy"); + //prepare + Configuration instance = new Configuration(); + String expectedResult = "test"; + //execute + instance.add(ConfigurationKeys.INSTALLED_BY, "test"); + //assert + assertEquals(expectedResult, instance.getInstalledBy()); + } + + /** + * Test of setInstalledBy method, of class Configuration. + */ + @Test + public void testSetInstalledBy() { + System.out.println("testSetInstalledBy"); + //prepare + Configuration instance = new Configuration(); + String expectedResult = "test"; + //execute + instance.setInstalledBy("test"); + //assert + assertEquals(expectedResult, instance.get(ConfigurationKeys.INSTALLED_BY)); + } + + /** + * Test of validateKey method, of class Configuration. + */ + @Test + public void testValidateKey() { + System.out.println("testValidateKey"); + //prepare + Configuration instance = new Configuration(); + //execute + Configuration.validateKey("dbmigration.hello"); + //assert + } + + /** + * Test of validateKey method, of class Configuration. + */ + @Test + public void testValidateKey2() { + System.out.println("testValidateKey2"); + //prepare + //execute + Throwable exception = assertThrows(DBMigrationException.class, () -> Configuration.validateKey("hello")); + assertEquals("Key does not start with prefix dbmigration.", exception.getMessage()); + //assert + } + + /** + * Test of startsKeyWithPrefix method, of class Configuration. + */ + @Test + public void testStartsKeyWithPrefix() { + System.out.println("testStartsKeyWithPrefix"); + //prepare + boolean expectedResult = true; + //execute + boolean result = Configuration.startsKeyWithPrefix("dbmigration.hello"); + //assert + assertEquals(expectedResult, result); + } + /** + * Test of startsKeyWithPrefix method, of class Configuration. + */ + @Test + public void testStartsKeyWithPrefix2() { + System.out.println("testStartsKeyWithPrefix2"); + //prepare + boolean expectedResult = false; + //execute + boolean result = Configuration.startsKeyWithPrefix("hello"); + //assert + assertEquals(expectedResult, result); + } + + /** + * Test of prependPrefixIfNeeded method, of class Configuration. + */ + @Test + public void testPrependPrefixIfNeeded() { + System.out.println("testPrependPrefixIfNeeded"); + //prepare + String expectedResult = "dbmigration.hello"; + //execute + String result = Configuration.prependPrefixIfNeeded("hello"); + //assert + assertEquals(expectedResult, result); + } + + /** + * Test of prependPrefixIfNeeded method, of class Configuration. + */ + @Test + public void testPrependPrefixIfNeeded2() { + System.out.println("testPrependPrefixIfNeeded2"); + //prepare + String expectedResult = "dbmigration.hello"; + //execute + String result = Configuration.prependPrefixIfNeeded("dbmigration.hello"); + //assert + assertEquals(expectedResult, result); + } + + /** + * Test of addAndAddPrefixIfNeeded method, of class Configuration. + */ + @Test + public void testAddAndAddPrefixIfNeeded_ConfigurationEntry() { + System.out.println("testAddAndAddPrefixIfNeeded_ConfigurationEntry"); + //prepare + ConfigurationEntry ce = new ConfigurationEntry("a", "p"); + Configuration conf = new Configuration(); + //execute + conf.addAndAddPrefixIfNeeded(ce); + //assert + assertTrue(conf.has("dbmigration.a")); + assertEquals("p", conf.get("dbmigration.a")); + } + + /** + * Test of addAndAddPrefixIfNeeded method, of class Configuration. + */ + @Test + public void testAddAndAddPrefixIfNeeded_String_String() { + System.out.println("testAddAndAddPrefixIfNeeded_String_String"); + //prepare + Configuration conf = new Configuration(); + //execute + conf.addAndAddPrefixIfNeeded("a", "p"); + //assert + assertTrue(conf.has("dbmigration.a")); + assertEquals("p", conf.get("dbmigration.a")); + } +} diff --git a/db-migration-core/src/test/java/org/nanoboot/dbmigration/entity/DBMigrationSchemaHistoryTest.java b/db-migration-core/src/test/java/org/nanoboot/dbmigration/entity/DBMigrationSchemaHistoryTest.java new file mode 100644 index 0000000..aae694b --- /dev/null +++ b/db-migration-core/src/test/java/org/nanoboot/dbmigration/entity/DBMigrationSchemaHistoryTest.java @@ -0,0 +1,157 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.entity; + +import java.security.NoSuchAlgorithmException; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.net.ssl.KeyManagerFactory; +import org.nanoboot.dbmigration.core.main.DBMigrationException; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +public class DBMigrationSchemaHistoryTest { + + public DBMigrationSchemaHistoryTest() { + } + + @BeforeAll + public static void setUpClass() { + } + + @AfterAll + public static void tearDownClass() { + } + + @BeforeEach + public void setUp() { + } + + @AfterEach + public void tearDown() { + } + + /** + * Test of calculateHash method, of class DBMigrationSchemaHistory. + */ + @Test + public void testCalculateHash() { + System.out.println("calculateHash"); + //prepare + String hashOfPreviousMigration = "4233137d1c510f2e55ba5cb220b864b11033f156"; + String hashOfScriptContentOfThisMigration = "dad372493dc2eeb685aac7fc48a27b6bed1b3af1"; + String expResult = "496cfd882d65c83c54a81065991096ae848bee68"; + //execute + String result = DBMigrationSchemaHistory.calculateHash(hashOfPreviousMigration, hashOfScriptContentOfThisMigration); + //assert + assertEquals(expResult, result); + } + + + /** + * Test of compareTo method, of class DBMigrationSchemaHistory. + */ + @Test + public void testCompareTo() { + System.out.println("compareTo"); + //prepare + DBMigrationSchemaHistory h1 = new DBMigrationSchemaHistory(); + DBMigrationSchemaHistory h2 = new DBMigrationSchemaHistory(); + DBMigrationSchemaHistory h3 = new DBMigrationSchemaHistory(); + DBMigrationSchemaHistory h4 = new DBMigrationSchemaHistory(); + h1.setInstalledRank(1); + h2.setInstalledRank(2); + h3.setInstalledRank(3); + h4.setInstalledRank(4); + // + h1.setMigrationGroup("group1"); + h2.setMigrationGroup("group1"); + h3.setMigrationGroup("group1"); + h4.setMigrationGroup("group1"); + // + int expectedResult_h1_h2 = -1; + int expectedResult_h1_h3 = -1; + int expectedResult_h1_h4 = -1; + int expectedResult_h2_h1 = 1; + int expectedResult_h2_h3 = -1; + int expectedResult_h2_h4 = -1; + int expectedResult_h3_h1 = 1; + int expectedResult_h3_h2 = 1; + int expectedResult_h3_h4 = -1; + int expectedResult_h4_h1 = 1; + int expectedResult_h4_h2 = 1; + int expectedResult_h4_h3 = 1; + //execute + int result_h1_h2 = h1.compareTo(h2); + int result_h1_h3 = h1.compareTo(h3); + int result_h1_h4 = h1.compareTo(h4); + int result_h2_h1 = h2.compareTo(h1); + int result_h2_h3 = h2.compareTo(h3); + int result_h2_h4 = h2.compareTo(h4); + int result_h3_h1 = h3.compareTo(h1); + int result_h3_h2 = h3.compareTo(h2); + int result_h3_h4 = h3.compareTo(h4); + int result_h4_h1 = h4.compareTo(h1); + int result_h4_h2 = h4.compareTo(h2); + int result_h4_h3 = h4.compareTo(h3); + //assert + assertEquals(expectedResult_h1_h2, result_h1_h2); + assertEquals(expectedResult_h1_h3, result_h1_h3); + assertEquals(expectedResult_h1_h4, result_h1_h4); + assertEquals(expectedResult_h2_h1, result_h2_h1); + assertEquals(expectedResult_h2_h3, result_h2_h3); + assertEquals(expectedResult_h2_h4, result_h2_h4); + assertEquals(expectedResult_h3_h1, result_h3_h1); + assertEquals(expectedResult_h3_h2, result_h3_h2); + assertEquals(expectedResult_h3_h4, result_h3_h4); + assertEquals(expectedResult_h4_h1, result_h4_h1); + assertEquals(expectedResult_h4_h2, result_h4_h2); + assertEquals(expectedResult_h4_h3, result_h4_h3); + } + + /** + * Test of compareTo method, of class DBMigrationSchemaHistory. + */ + @Test + public void testCompareTo2() { + System.out.println("compareTo2"); + //prepare + DBMigrationSchemaHistory h1 = new DBMigrationSchemaHistory(); + DBMigrationSchemaHistory h2 = new DBMigrationSchemaHistory(); + h1.setInstalledRank(1); + h2.setInstalledRank(2); + // + h1.setMigrationGroup("group1"); + h2.setMigrationGroup("group2"); + //execute + Throwable exception = assertThrows(DBMigrationException.class, () -> h1.compareTo(h2)); + assertEquals("Cannot compare, if migration groups are different: this.getMigrationGroup()=group1, o.getMigrationGroup()=group2", exception.getMessage()); + //assert + } +} diff --git a/db-migration-core/src/test/java/org/nanoboot/dbmigration/resources/FileSystemSqlFileProviderTest.java b/db-migration-core/src/test/java/org/nanoboot/dbmigration/resources/FileSystemSqlFileProviderTest.java new file mode 100644 index 0000000..f729183 --- /dev/null +++ b/db-migration-core/src/test/java/org/nanoboot/dbmigration/resources/FileSystemSqlFileProviderTest.java @@ -0,0 +1,118 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.resources; + +import java.io.File; +import java.util.Collections; +import java.util.List; +import org.nanoboot.dbmigration.core.main.DBMigrationException; +import static org.nanoboot.dbmigration.core.utils.DBMigrationUtils.writeToFile; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +public class FileSystemSqlFileProviderTest { + + public FileSystemSqlFileProviderTest() { + } + + @BeforeAll + public static void setUpClass() { + } + + @AfterAll + public static void tearDownClass() { + } + + @BeforeEach + public void setUp() { + } + + @AfterEach + public void tearDown() { + } + + /** + * Test of provide method, of class FileSystemSqlFileProvider. + */ + @Test + public void testProvide() { + System.out.println("provide"); + //prepare + File dir = new File("tmp_test_dir_" + ((int) (Math.random() * 1000000))); + dir.mkdir(); + String dirPath = dir.getAbsolutePath(); + File file1 = new File(dirPath + File.separator + "V000001__create_table_teacher.sql"); + File file2 = new File(dirPath + File.separator + "V000002__create_table_student.sql"); + File file3 = new File(dirPath + File.separator + "V000003__create_table_class.sql"); + writeToFile(file1.getAbsolutePath(), "aaa"); + writeToFile(file2.getAbsolutePath(), "bbb"); + writeToFile(file3.getAbsolutePath(), "ccc"); + Class clazz = null; + FileSystemSqlFileProvider instance = new FileSystemSqlFileProvider(); + //execute + List result = instance.provide(dirPath, clazz); + file1.delete(); + file2.delete(); + file3.delete(); + dir.delete(); + Collections.sort(result); + //assert + assertEquals(3, result.size()); + assertEquals("V000001__create_table_teacher.sql", result.get(0).getFileName()); + assertEquals("V000002__create_table_student.sql", result.get(1).getFileName()); + assertEquals("V000003__create_table_class.sql", result.get(2).getFileName()); + } + + /** + * Test of provide method, of class FileSystemSqlFileProvider. + */ + @Test + public void testProvide2() { + System.out.println("provide2"); + //prepare + File dir = new File("tmp_test_dir_" + ((int) (Math.random() * 1000000))); + dir.mkdir(); + File dir2 = new File(dir.getAbsolutePath() + File.separator + ((int) (Math.random() * 1000000)) + ((int) (Math.random() * 1000000))); + dir2.mkdir(); + String dirPath = dir.getAbsolutePath(); + File file1 = new File(dirPath + File.separator + "V000001__create_table_teacher.sql"); + writeToFile(file1.getAbsolutePath(), "aaa"); + Class clazz = null; + FileSystemSqlFileProvider instance = new FileSystemSqlFileProvider(); + //execute + Throwable exception = assertThrows(DBMigrationException.class, () -> instance.provide(dirPath, clazz)); + file1.delete(); + dir2.delete(); + dir.delete(); + assertEquals(true, exception.getMessage().endsWith("is directory, sqlMigrationsDirectory cannot contain any directory.")); + //assert + } + + +} diff --git a/db-migration-core/src/test/java/org/nanoboot/dbmigration/resources/ResourcesSqlFileProviderTest.java b/db-migration-core/src/test/java/org/nanoboot/dbmigration/resources/ResourcesSqlFileProviderTest.java new file mode 100644 index 0000000..4d174fa --- /dev/null +++ b/db-migration-core/src/test/java/org/nanoboot/dbmigration/resources/ResourcesSqlFileProviderTest.java @@ -0,0 +1,113 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.resources; + +import java.util.List; +import org.nanoboot.dbmigration.core.main.DBMigrationException; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +public class ResourcesSqlFileProviderTest { + + public ResourcesSqlFileProviderTest() { + } + + @BeforeAll + public static void setUpClass() { + } + + @AfterAll + public static void tearDownClass() { + } + + @BeforeEach + public void setUp() { + } + + @AfterEach + public void tearDown() { + } + + /** + * Test of createPath method, of class ResourcesSqlFileProvider. + */ + @Test + public void testCreatePath() { + System.out.println("createPath"); + //prepare + String sqlDialect = "sqlite"; + String nameOfMigrations = "testa"; + String expResult = "db_migrations/sqlite/testa"; + //test + String result = ResourcesSqlFileProvider.createPath(sqlDialect, nameOfMigrations); + //assert + assertEquals(expResult, result); + } + + /** + * Test of provide method, of class ResourcesSqlFileProvider. + */ + @Test + public void testProvide_String() { + System.out.println("provide(String)"); + //prepare + String path = ResourcesSqlFileProvider.createPath("sqlite", "test"); + Class clazz = ResourcesSqlFileProvider.class; + ResourcesSqlFileProvider instance = new ResourcesSqlFileProvider(); + List expResult = null; + //execute + Throwable exception = assertThrows(UnsupportedOperationException.class, () -> instance.provide(path)); + + //assert + } + + /** + * Test of provide method, of class ResourcesSqlFileProvider. + */ + @Test + public void testProvide_String_Class() { + System.out.println("provide(String,Class)"); + //prepare + String path = ResourcesSqlFileProvider.createPath("sqlite", "test"); + Class clazz = org.nanoboot.dbmigration.test.jar.DBMigrationTestJarDummyClass.class; + ResourcesSqlFileProvider instance = new ResourcesSqlFileProvider(); + List expResult = null; + //execute + try{ + List result = instance.provide(path,clazz); + }catch(Exception e) { + System.err.println("###"+e.getMessage()); + throw e; + } + //assert + //assertEquals(12, result.size()); + //assertEquals(expResult, result); + } + +} diff --git a/db-migration-core/src/test/java/org/nanoboot/dbmigration/resources/SqlFileNameTest.java b/db-migration-core/src/test/java/org/nanoboot/dbmigration/resources/SqlFileNameTest.java new file mode 100644 index 0000000..3974aea --- /dev/null +++ b/db-migration-core/src/test/java/org/nanoboot/dbmigration/resources/SqlFileNameTest.java @@ -0,0 +1,399 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.resources; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import org.nanoboot.dbmigration.core.main.DBMigrationException; +import org.nanoboot.dbmigration.core.entity.DBMigrationSchemaHistory; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +public class SqlFileNameTest { + + public SqlFileNameTest() { + } + + @org.junit.jupiter.api.BeforeAll + public static void setUpClass() throws Exception { + } + + @org.junit.jupiter.api.AfterAll + public static void tearDownClass() throws Exception { + } + + @org.junit.jupiter.api.BeforeEach + public void setUp() throws Exception { + } + + @org.junit.jupiter.api.AfterEach + public void tearDown() throws Exception { + } + + //V2_1__First_Changes.sql + /** + * Test of SqlFileName constructor, of class SqlFileName. + */ + @org.junit.jupiter.api.Test + public void testConstructor_2args_OK() { + System.out.println("testConstructor_2args_OK"); + SqlFileName sqlFileName = new SqlFileName("V002_001__First_Changes.sql"); + String expFileName = "V002_001__First_Changes.sql"; + String expVersion = "2.1"; + String expDescription = "First Changes"; + assertEquals(expFileName, sqlFileName.getFileName()); + assertEquals(expVersion, sqlFileName.getVersion()); + assertEquals(expDescription, sqlFileName.getDescription()); + } + + /** + * Test of SqlFileName constructor, of class SqlFileName. + */ + @org.junit.jupiter.api.Test + public void testConstructor_2args_OK2() { + System.out.println("testConstructor_2args_OK2"); + SqlFileName sqlFileName = new SqlFileName("V2_001__First_Changes.sql"); + String expFileName = "V2_001__First_Changes.sql"; + String expVersion = "2.1"; + String expDescription = "First Changes"; + assertEquals(expFileName, sqlFileName.getFileName()); + assertEquals(expVersion, sqlFileName.getVersion()); + assertEquals(expDescription, sqlFileName.getDescription()); + } + + /** + * Test of SqlFileName constructor, of class SqlFileName. + */ + @org.junit.jupiter.api.Test + public void testConstructor_2args_OK3() { + System.out.println("testConstructor_2args_OK3"); + SqlFileName sqlFileName = new SqlFileName("V002_1__First_Changes.sql"); + String expFileName = "V002_1__First_Changes.sql"; + String expVersion = "2.1"; + String expDescription = "First Changes"; + assertEquals(expFileName, sqlFileName.getFileName()); + assertEquals(expVersion, sqlFileName.getVersion()); + assertEquals(expDescription, sqlFileName.getDescription()); + } + + /** + * Test of SqlFileName constructor, of class SqlFileName. + */ + @org.junit.jupiter.api.Test + public void testConstructor_2args_OK4() { + System.out.println("testConstructor_2args_OK4"); + SqlFileName sqlFileName = new SqlFileName("V2_1__First_Changes.sql"); + String expFileName = "V2_1__First_Changes.sql"; + String expVersion = "2.1"; + String expDescription = "First Changes"; + assertEquals(expFileName, sqlFileName.getFileName()); + assertEquals(expVersion, sqlFileName.getVersion()); + assertEquals(expDescription, sqlFileName.getDescription()); + } + + /** + * Test of SqlFileName constructor, of class SqlFileName. + */ + @org.junit.jupiter.api.Test + public void testConstructor_2args_OK5() { + System.out.println("testConstructor_2args_OK5"); + SqlFileName sqlFileName = new SqlFileName("V2_1_000003_5__First_Changes.sql"); + String expFileName = "V2_1_000003_5__First_Changes.sql"; + String expVersion = "2.1.3.5"; + String expDescription = "First Changes"; + assertEquals(expFileName, sqlFileName.getFileName()); + assertEquals(expVersion, sqlFileName.getVersion()); + assertEquals(expDescription, sqlFileName.getDescription()); + } + + /** + * Test of SqlFileName constructor, of class SqlFileName. + */ + @org.junit.jupiter.api.Test + public void testConstructor_2args_OK6() { + System.out.println("testConstructor_2args_OK6"); + SqlFileName sqlFileName = new SqlFileName("V2_1_3_5__First_Changes.sql"); + String expFileName = "V2_1_3_5__First_Changes.sql"; + String expVersion = "2.1.3.5"; + String expDescription = "First Changes"; + assertEquals(expFileName, sqlFileName.getFileName()); + assertEquals(expVersion, sqlFileName.getVersion()); + assertEquals(expDescription, sqlFileName.getDescription()); + } + + /** + * Test of SqlFileName constructor, of class SqlFileName. + */ + @org.junit.jupiter.api.Test + public void testConstructor_2args_OK7() { + System.out.println("testConstructor_2args_OK7"); + SqlFileName sqlFileName = new SqlFileName("V4__First_Changes.sql"); + String expFileName = "V4__First_Changes.sql"; + String expVersion = "4"; + String expDescription = "First Changes"; + assertEquals(expFileName, sqlFileName.getFileName()); + assertEquals(expVersion, sqlFileName.getVersion()); + assertEquals(expDescription, sqlFileName.getDescription()); + } + + /** + * Test of SqlFileName constructor, of class SqlFileName. + */ + @org.junit.jupiter.api.Test + public void testConstructor_2args_OK8() { + System.out.println("testConstructor_2args_OK8"); + SqlFileName sqlFileName = new SqlFileName("V4_0__First_Changes.sql"); + String expFileName = "V4_0__First_Changes.sql"; + String expVersion = "4.0"; + String expDescription = "First Changes"; + assertEquals(expFileName, sqlFileName.getFileName()); + assertEquals(expVersion, sqlFileName.getVersion()); + assertEquals(expDescription, sqlFileName.getDescription()); + } + + /** + * Test of SqlFileName constructor, of class SqlFileName. + */ + @org.junit.jupiter.api.Test + public void testConstructor_2args_OK9() { + System.out.println("testConstructor_2args_OK9"); + SqlFileName sqlFileName = new SqlFileName("V4_000__First_Changes.sql"); + String expFileName = "V4_000__First_Changes.sql"; + String expVersion = "4.0"; + String expDescription = "First Changes"; + assertEquals(expFileName, sqlFileName.getFileName()); + assertEquals(expVersion, sqlFileName.getVersion()); + assertEquals(expDescription, sqlFileName.getDescription()); + } + + /** + * Test of SqlFileName constructor, of class SqlFileName. + */ + @org.junit.jupiter.api.Test + public void testConstructor_2args_KO() { + System.out.println("testConstructor_2args_KO"); + + Throwable exception = assertThrows(DBMigrationException.class, () -> new SqlFileName("B4_000__First_Changes.sql")); + assertEquals("File B4_000__First_Changes.sql does not start with \"V\".", exception.getMessage()); + + } + + /** + * Test of SqlFileName constructor, of class SqlFileName. + */ + @org.junit.jupiter.api.Test + public void testConstructor_2args_KO2() { + System.out.println("testConstructor_2args_KO2"); + + Throwable exception = assertThrows(DBMigrationException.class, () -> new SqlFileName("V4_000_First_Changes.sql")); + assertEquals("File V4_000_First_Changes.sql does not contain \"__\".", exception.getMessage()); + + } + + /** + * Test of calculateHash method, of class SqlFile. + */ + @Test + public void testConstructor_2args_KO3() { + System.out.println("testConstructor_2args_KO3"); + //prepare + String fileName = "V002_001__First_Changes.txt"; + //execute + //assert + Throwable exception = assertThrows(DBMigrationException.class, () -> new SqlFileName(fileName)); + assertEquals("File V002_001__First_Changes.txt does not end with \".sql\".", exception.getMessage()); + } + /** + * Test of compareTo method, of class SqlFile. + */ + @org.junit.jupiter.api.Test + public void testCompareTo() { + System.out.println("compareTo"); + //prepare + SqlFile sf1 = new SqlFile("V4_0__First_Changes.sql", "select 1;"); + SqlFile sf2 = new SqlFile("V4_0_1__First_Changes2.sql", "select 1;"); + SqlFile sf3 = new SqlFile("V4_0_2__First_Changes3.sql", "select 1;"); + SqlFile sf4 = new SqlFile("V4_1__First_Changes4.sql", "select 1;"); + SqlFile sf5 = new SqlFile("V4_1_2__First_Changes5.sql", "select 1;"); + SqlFile sf6 = new SqlFile("V4_2_3__First_Changes6.sql", "select 1;"); + SqlFile sf7 = new SqlFile("V4_2_4__First_Changes7.sql", "select 1;"); + SqlFile sf8 = new SqlFile("V5_1_4__First_Changes8.sql", "select 1;"); + SqlFile sf9 = new SqlFile("V5_1_5__First_Changes9.sql", "select 1;"); + SqlFile sf10 = new SqlFile("V9_9_9_0__First_Changes10.sql", "select 1;"); + SqlFile sf11 = new SqlFile("V9_9_9_1__First_Changes11.sql", "select 1;"); + SqlFile sf12 = new SqlFile("V9_9_9_9__First_Changes12.sql", "select 1;"); + SqlFile sf13 = new SqlFile("V9_9_9_9_1__First_Changes13.sql", "select 1;"); + SqlFile sf14 = new SqlFile("V9_9_9_9_4__First_Changes14.sql", "select 1;"); + List sqlFilesOrig = new ArrayList<>(); + sqlFilesOrig.add(sf1); + sqlFilesOrig.add(sf2); + sqlFilesOrig.add(sf3); + sqlFilesOrig.add(sf4); + sqlFilesOrig.add(sf5); + sqlFilesOrig.add(sf6); + sqlFilesOrig.add(sf7); + sqlFilesOrig.add(sf8); + sqlFilesOrig.add(sf9); + sqlFilesOrig.add(sf10); + sqlFilesOrig.add(sf11); + sqlFilesOrig.add(sf12); + sqlFilesOrig.add(sf13); + sqlFilesOrig.add(sf14); + List sqlFiles = new ArrayList<>(); + sqlFiles.add(sf1); + sqlFiles.add(sf2); + sqlFiles.add(sf3); + sqlFiles.add(sf4); + sqlFiles.add(sf5); + sqlFiles.add(sf6); + sqlFiles.add(sf7); + sqlFiles.add(sf8); + sqlFiles.add(sf9); + sqlFiles.add(sf10); + sqlFiles.add(sf11); + sqlFiles.add(sf12); + sqlFiles.add(sf13); + sqlFiles.add(sf14); + Collections.shuffle(sqlFiles); + StringBuilder sb = new StringBuilder(); + for(SqlFile sf:sqlFilesOrig) { + sb.append(sf.getFileName()); + sb.append("####"); + } + String expResult = sb.toString(); + //execute + Collections.sort(sqlFiles); + StringBuilder sb2 = new StringBuilder(); + for(SqlFile sf:sqlFiles) { + sb2.append(sf.getFileName()); + sb2.append("####"); + } + String returnedResult = sb2.toString(); + //assert + assertEquals(expResult, returnedResult); + } + /** + * Test of compareTo method, of class SqlFile. + */ + @org.junit.jupiter.api.Test + public void testCompareTo2() { + System.out.println("testCompareTo2"); + //prepare + SqlFileName sf1 = new SqlFileName("V4_0_1__First_Changes.sql"); + SqlFileName sf2 = new SqlFileName("V4_0_1__First_Changes2.sql"); + //execute + Throwable exception = assertThrows(DBMigrationException.class, () -> sf1.compareTo(sf2)); + System.out.println("e=" + exception.getMessage()); + assertEquals(true , exception.getMessage().startsWith("Cannot compare instances of SqlFileName with same version and different file names:")); + //assert + } + + /** + * Test of compareTo method, of class SqlFile. + */ + @org.junit.jupiter.api.Test + public void testCompareTo3() { + System.out.println("testCompareTo3"); + //prepare + SqlFileName sf1 = new SqlFileName("V4_0_1__First_Changes.sql"); + SqlFileName sf2 = new SqlFileName("V4_0_1__First_Changes.sql"); + //execute + int result = sf1.compareTo(sf2); + final int expectedResult = 0; + //assert + assertEquals(expectedResult, result); + } + + /** + * Test of compareTo method, of class SqlFile. + */ + @org.junit.jupiter.api.Test + public void testCompareTo4() { + System.out.println("compareTo"); + //prepare + String data = """ + V000001__create_table_test1.sql + V000001_1__add_column_column1.sql + V000010__add_column_column1.sql + V000011__add_column_column1.sql + V000012__add_column_column1.sql + V000002_0__add_column_column1.sql + V000002_1__add_column_column1.sql + V000002_2__add_column_column1.sql + V000002_3__add_column_column1.sql + V000002_4__add_column_column1.sql + V000002_5__add_column_column1.sql + V000009__add_column_column1.sql + """; + List sqlFileNames = new ArrayList<>(); + for(String s:data.split("\\r?\\n")) { + SqlFileName sfn=new SqlFileName(s); + sqlFileNames.add(sfn); + } + + String expResult = """ + V000001__create_table_test1.sql + V000001_1__add_column_column1.sql + V000002_0__add_column_column1.sql + V000002_1__add_column_column1.sql + V000002_2__add_column_column1.sql + V000002_3__add_column_column1.sql + V000002_4__add_column_column1.sql + V000002_5__add_column_column1.sql + V000009__add_column_column1.sql + V000010__add_column_column1.sql + V000011__add_column_column1.sql + V000012__add_column_column1.sql + """; + //execute + Collections.sort(sqlFileNames); + StringBuilder sb = new StringBuilder(); + for(SqlFileName sfn:sqlFileNames) { + sb.append(sfn.getFileName()); + sb.append("\n"); + } + String returnedResult = sb.toString(); + //assert + assertEquals(expResult, returnedResult); + } + + /** + * Test of compareTo method, of class SqlFile. + */ + @org.junit.jupiter.api.Test + public void testCompareTo5() { + System.out.println("compareTo"); + //prepare + SqlFileName sfn1 = new SqlFileName("V000010__add_column_column1.sql"); + SqlFileName sfn2 = new SqlFileName("V000002_0__add_column_column1.sql"); + int expResult = 1; + //execute + int returnedResult = sfn1.compareTo(sfn2); + + //assert + assertEquals(expResult, returnedResult); + } +} diff --git a/db-migration-core/src/test/java/org/nanoboot/dbmigration/resources/SqlFileProviderTest.java b/db-migration-core/src/test/java/org/nanoboot/dbmigration/resources/SqlFileProviderTest.java new file mode 100644 index 0000000..9b57cdb --- /dev/null +++ b/db-migration-core/src/test/java/org/nanoboot/dbmigration/resources/SqlFileProviderTest.java @@ -0,0 +1,83 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.resources; + +import java.util.List; +import lombok.Getter; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +public class SqlFileProviderTest { + + public SqlFileProviderTest() { + } + + @BeforeAll + public static void setUpClass() { + } + + @AfterAll + public static void tearDownClass() { + } + + @BeforeEach + public void setUp() { + } + + @AfterEach + public void tearDown() { + } + + /** + * Test of provide method, of class SqlFileProvider. + */ + @Test + public void testProvide_String() { + System.out.println("provide"); + //prepare + SqlFileProviderImpl sfpi = new SqlFileProviderImpl(); + //execute + sfpi.provide("somePath"); + //assert + assertEquals(true, sfpi.wasClazzPassedAndItIsNull); + } + + public class SqlFileProviderImpl implements SqlFileProvider { + + private boolean wasClazzPassedAndItIsNull = false; + + public List provide(String path, Class clazz) { + if (clazz == null) { + wasClazzPassedAndItIsNull = true; + } + return null; + } + } + +} diff --git a/db-migration-core/src/test/java/org/nanoboot/dbmigration/resources/SqlFileTest.java b/db-migration-core/src/test/java/org/nanoboot/dbmigration/resources/SqlFileTest.java new file mode 100644 index 0000000..dcde9ec --- /dev/null +++ b/db-migration-core/src/test/java/org/nanoboot/dbmigration/resources/SqlFileTest.java @@ -0,0 +1,100 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.resources; + +import org.nanoboot.dbmigration.core.main.DBMigrationException; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +public class SqlFileTest { + + public SqlFileTest() { + } + + @BeforeAll + public static void setUpClass() { + } + + @AfterAll + public static void tearDownClass() { + } + + @BeforeEach + public void setUp() { + } + + @AfterEach + public void tearDown() { + } + /** + * Test of calculateHash method, of class SqlFile. + */ + @Test + public void testConstructor_String_String() { + System.out.println("testConstructor_String_String"); + //prepare + SqlFile instance; + //execute + instance = new SqlFile("V002_001__First_Changes.sql","select 1;"); + //assert + assertEquals("V002_001__First_Changes.sql", instance.getFileName()); + assertEquals("select 1;", instance.getContent()); + } + + /** + * Test of calculateHash method, of class SqlFile. + */ + @Test + public void testCalculateHash() { + System.out.println("testCalculateHash"); + //prepare + SqlFile instance = new SqlFile("V002_001__First_Changes.sql","select 1;"); + String expResult = "4f619e84816024661eb6dd1247713f342da23364"; + //execute + String result = instance.calculateHash(); + //assert + assertEquals(expResult, result); + } + +// /** +// * Test of compareTo method, of class SqlFile. +// */ +// @Test +// public void testCompareTo() { +// System.out.println("compareTo"); +// SqlFile o = null; +// SqlFile instance = null; +// int expResult = 0; +// int result = instance.compareTo(o); +// assertEquals(expResult, result); +// // TODO review the generated test code and remove the default call to fail. +// fail("The test case is a prototype."); +// } + +} diff --git a/db-migration-core/src/test/java/org/nanoboot/dbmigration/utils/DBMigrationUtilsTest.java b/db-migration-core/src/test/java/org/nanoboot/dbmigration/utils/DBMigrationUtilsTest.java new file mode 100644 index 0000000..486eb81 --- /dev/null +++ b/db-migration-core/src/test/java/org/nanoboot/dbmigration/utils/DBMigrationUtilsTest.java @@ -0,0 +1,95 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.core.utils; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Modifier; +import lombok.experimental.Helper; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +public class DBMigrationUtilsTest { + + public DBMigrationUtilsTest() { + } + + @BeforeAll + public static void setUpClass() { + } + + @AfterAll + public static void tearDownClass() { + } + + @BeforeEach + public void setUp() { + } + + @AfterEach + public void tearDown() { + } + + @Test + public void DBMigrationUtils_constructor_noArgs() throws SecurityException, NoSuchMethodException { + //prepare + Constructor constructor = DBMigrationUtils.class.getDeclaredConstructor(); + //execute + //assert + assertTrue(Modifier.isPrivate(constructor.getModifiers()), "Constructor is not private"); + constructor.setAccessible(true); + Throwable exception = assertThrows(java.lang.reflect.InvocationTargetException.class, () -> constructor.newInstance()); + } +// /** +// * Test of writeToFile method, of class DBMigrationUtils. +// */ +// @Test +// public void testWriteToFile() { +// System.out.println("writeToFile"); +// String path = ""; +// String text = ""; +// DBMigrationUtils.writeToFile(path, text); +// // TODO review the generated test code and remove the default call to fail. +// fail("The test case is a prototype."); +// } +// +// /** +// * Test of readTextFromFile method, of class DBMigrationUtils. +// */ +// @Test +// public void testReadTextFromFile() { +// System.out.println("readTextFromFile"); +// String path = ""; +// String expResult = ""; +// String result = DBMigrationUtils.readTextFromFile(path); +// assertEquals(expResult, result); +// // TODO review the generated test code and remove the default call to fail. +// fail("The test case is a prototype."); +// } + +} diff --git a/db-migration-test-jar/pom.xml b/db-migration-test-jar/pom.xml new file mode 100644 index 0000000..ee3d257 --- /dev/null +++ b/db-migration-test-jar/pom.xml @@ -0,0 +1,210 @@ + + + + 4.0.0 + + + org.nanoboot.tools.dbmigration + db-migration + 0.1.0-SNAPSHOT + + + org.nanoboot.tools.dbmigration + db-migration-test-jar + jar + + DB Migration Test Jar + Test jar for tool migrating databases versions. + + + + + + + + + + org.apache.maven.plugins + maven-deploy-plugin + ${maven-deploy-plugin.version} + + + + + + org.codehaus.mojo + build-helper-maven-plugin + ${build-helper-maven-plugin.version} + + + add-resource + generate-resources + + add-resource + + + + + src/main/resources/db_migrations/sqlite/test + db_migrations/sqlite/test + + *.sql + + + + + + + + + org.jacoco + jacoco-maven-plugin + ${jacoco-maven-plugin.version} + + + + prepare-agent + + + + + report + test + + report + + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + ${checkstyle.skip} + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + + + + org.projectlombok + lombok + ${lombok.version} + + + ${javase.version} + ${javase.version} + + + + maven-surefire-plugin + ${maven-surefire-plugin.version} + + + maven-failsafe-plugin + ${maven-surefire-plugin.version} + + + + + + + org.flywaydb + flyway-core + ${flyway-core.version} + + + + org.projectlombok + lombok + ${lombok.version} + provided + + + org.xerial + sqlite-jdbc + ${sqlite-jdbc.version} + + + + org.nanoboot.powerframework + power-time + ${power.version} + + + org.nanoboot.powerframework + power-core + ${power.version} + + + org.nanoboot.powerframework + power-security + ${power.version} + + + org.apache.logging.log4j + log4j-api + ${log4j.version} + + + + org.apache.logging.log4j + log4j-core + ${log4j.version} + + + + org.junit.jupiter + junit-jupiter-api + ${junit-jupiter.version} + test + + + org.junit.jupiter + junit-jupiter-engine + ${junit-jupiter.version} + test + + + org.junit.jupiter + junit-jupiter-params + ${junit-jupiter.version} + test + + + + org.mockito + mockito-inline + ${mockito-inline.version} + test + + + + + diff --git a/db-migration-test-jar/src/main/java/lombok.config b/db-migration-test-jar/src/main/java/lombok.config new file mode 100644 index 0000000..b6d6306 --- /dev/null +++ b/db-migration-test-jar/src/main/java/lombok.config @@ -0,0 +1,4 @@ +# tells Lombok that this is the root directory and that it shouldn’t search parent directories for more configuration files +config.stopBubbling = true +# tells Lombok to add @lombok.Generated annotation to all generated methods +lombok.addLombokGeneratedAnnotation = true diff --git a/db-migration-test-jar/src/main/java/module-info.java b/db-migration-test-jar/src/main/java/module-info.java new file mode 100644 index 0000000..e284bb6 --- /dev/null +++ b/db-migration-test-jar/src/main/java/module-info.java @@ -0,0 +1,35 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +module dbmigration.testjar { + requires org.flywaydb.core; + requires lombok; + requires java.sql; + requires powerframework.time; + requires powerframework.core; + requires powerframework.security; + requires org.apache.logging.log4j; + requires org.apache.logging.log4j.core; + exports org.nanoboot.dbmigration.test.jar; +} diff --git a/db-migration-test-jar/src/main/java/org/nanoboot/dbmigration/test/jar/DBMigrationTestJarDummyClass.java b/db-migration-test-jar/src/main/java/org/nanoboot/dbmigration/test/jar/DBMigrationTestJarDummyClass.java new file mode 100644 index 0000000..d5b9a39 --- /dev/null +++ b/db-migration-test-jar/src/main/java/org/nanoboot/dbmigration/test/jar/DBMigrationTestJarDummyClass.java @@ -0,0 +1,29 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// db-migration: A database schema versioning tool. +// Copyright (C) 2021-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.dbmigration.test.jar; + +/** + * + * @author Robert Vokac + * @since 0.1.0 + */ +public class DBMigrationTestJarDummyClass { + +} diff --git a/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000001_1__add_column_column1.sql b/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000001_1__add_column_column1.sql new file mode 100644 index 0000000..2894d09 --- /dev/null +++ b/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000001_1__add_column_column1.sql @@ -0,0 +1,2 @@ +ALTER TABLE TEST_RC +ADD COLUMN column1; diff --git a/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000001__create_table_test1.sql b/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000001__create_table_test1.sql new file mode 100644 index 0000000..6d40c85 --- /dev/null +++ b/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000001__create_table_test1.sql @@ -0,0 +1,7 @@ + +CREATE TABLE "TEST_RC" ( + "ID" TEXT NOT NULL UNIQUE, + "NAME" TEXT NOT NULL, + "SURNAME" TEXT NOT NULL, + PRIMARY KEY("ID") +); diff --git a/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000002_0__add_column_column1.sql b/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000002_0__add_column_column1.sql new file mode 100644 index 0000000..7bcc0bb --- /dev/null +++ b/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000002_0__add_column_column1.sql @@ -0,0 +1,2 @@ +ALTER TABLE TEST_RC +ADD COLUMN column2; diff --git a/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000002_1__add_column_column1.sql b/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000002_1__add_column_column1.sql new file mode 100644 index 0000000..7aea11b --- /dev/null +++ b/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000002_1__add_column_column1.sql @@ -0,0 +1,2 @@ +ALTER TABLE TEST_RC +ADD COLUMN column3 text; diff --git a/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000002_2__add_column_column1.sql b/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000002_2__add_column_column1.sql new file mode 100644 index 0000000..0823204 --- /dev/null +++ b/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000002_2__add_column_column1.sql @@ -0,0 +1,2 @@ +ALTER TABLE TEST_RC +ADD COLUMN column4 integer; diff --git a/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000002_3__add_column_column1.sql b/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000002_3__add_column_column1.sql new file mode 100644 index 0000000..3b67822 --- /dev/null +++ b/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000002_3__add_column_column1.sql @@ -0,0 +1,2 @@ +ALTER TABLE TEST_RC +ADD COLUMN column5 text; diff --git a/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000002_4__add_column_column1.sql b/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000002_4__add_column_column1.sql new file mode 100644 index 0000000..f269976 --- /dev/null +++ b/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000002_4__add_column_column1.sql @@ -0,0 +1,2 @@ +ALTER TABLE TEST_RC +ADD COLUMN column6 text; diff --git a/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000002_5__add_column_column1.sql b/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000002_5__add_column_column1.sql new file mode 100644 index 0000000..04190ae --- /dev/null +++ b/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000002_5__add_column_column1.sql @@ -0,0 +1,2 @@ +ALTER TABLE TEST_RC +ADD COLUMN column7 text; diff --git a/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000009__add_column_column1.sql b/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000009__add_column_column1.sql new file mode 100644 index 0000000..25f4704 --- /dev/null +++ b/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000009__add_column_column1.sql @@ -0,0 +1,2 @@ +ALTER TABLE TEST_RC +ADD COLUMN column8 text; diff --git a/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000010__add_column_column1.sql b/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000010__add_column_column1.sql new file mode 100644 index 0000000..6d786d6 --- /dev/null +++ b/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000010__add_column_column1.sql @@ -0,0 +1,2 @@ +ALTER TABLE TEST_RC +ADD COLUMN column9 text; diff --git a/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000011__add_column_column1.sql b/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000011__add_column_column1.sql new file mode 100644 index 0000000..7d55c92 --- /dev/null +++ b/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000011__add_column_column1.sql @@ -0,0 +1,2 @@ +ALTER TABLE TEST_RC +ADD COLUMN column10 text; diff --git a/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000012__add_column_column1.sql b/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000012__add_column_column1.sql new file mode 100644 index 0000000..c81dcd9 --- /dev/null +++ b/db-migration-test-jar/src/main/resources/db_migrations/sqlite/test/V000012__add_column_column1.sql @@ -0,0 +1,2 @@ +ALTER TABLE TEST_RC +ADD COLUMN column11 text; diff --git a/db-migration-test-jar/src/test/java/.gitkeep b/db-migration-test-jar/src/test/java/.gitkeep new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/db-migration-test-jar/src/test/java/.gitkeep @@ -0,0 +1 @@ + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..6eb2810 --- /dev/null +++ b/pom.xml @@ -0,0 +1,68 @@ + + + + 4.0.0 + + + org.nanoboot.common + nanoboot-parent + 0.1.0-SNAPSHOT + + + org.nanoboot.tools.dbmigration + db-migration + 0.1.0-SNAPSHOT + pom + + DB Migration + Tool migrating databases versions. + + + 0.1.0-SNAPSHOT + UTF-8 + true + 0.1.0-SNAPSHOT + + + db-migration-core + db-migration-test-jar + + + + + + org.apache.maven.plugins + maven-deploy-plugin + ${maven-deploy-plugin.version} + + + + + + + + + + + + + diff --git a/release.sh b/release.sh new file mode 100755 index 0000000..60f2e82 --- /dev/null +++ b/release.sh @@ -0,0 +1,99 @@ +#! /bin/bash + +set -e + +currentDir=`pwd` + +### Set, if needed: +pomParentDir=. + +stepCount=13 + +fromStepCount="/"$stepCount + +echo "### Release of new version of a Maven artifact ###" + + +read -p "Current version (to be released now, example: 1.2.3):" currentVersion +echo "Current version=" $currentVersion + +read -p "Next version (example: 1.2.3):" nextVersion +echo "Next version=" nextVersion + +echo Step : 1$fromStepCount : Deploy current snapshot to Maven repository +cd $pomParentDir +mvn clean deploy&&echo "DONE" +cd $currentDir + +echo Step : 2$fromStepCount : Delete -SNAPSHOT- all occurences in poms + +echo "Note: replace " $currentVersion-SNAPSHOT" by " $currentVersion "in all occurrences for this artifact:" +read -p "Have you deleted all the occurences (y/n)?" choice +case "$choice" in + y|Y ) echo "yes"&&echo "DONE";; + n|N ) echo "no";; + * ) echo "invalid"&&exit;; +esac + +echo Step : 3$fromStepCount : Deploy released version to Maven repository +cd $pomParentDir +mvn clean deploy&&echo "DONE" +cd $currentDir + +echo Step : 4$fromStepCount : Add the deletion to git +git add .&&echo "DONE" + + +echo Step : 5$fromStepCount : Commit the released version to git +git commit -m "Released $currentVersion"&&echo "DONE" + + +#git tag -d 0.0.0 +#git push --delete origin 0.0.0 + +echo Step : 6$fromStepCount : Tag released version +#git tag -a $currentVersion -m "$currentVersion"&&echo "DONE" +git tag $currentVersion&&echo "DONE" + + +echo Step : 7$fromStepCount : Push to git +#git push -f origin HEAD; +git push origin HEAD&&echo "DONE" + + +echo Step : 8$fromStepCount : Push new tag to git +git push origin $currentVersion&&echo "DONE" + +echo Step : 9$fromStepCount : Increase version and add -SNAPSHOST \(example: 999.999.999-SNAPSHOT\) +echo "Note: replace " $currentVersion " by " $nextVersion"-SNAPSHOT" + +read -p "Have you replaced all the occurrences (y/n)?" choice +case "$choice" in + y|Y ) echo "yes"&&echo "DONE";; + n|N ) echo "no";; + * ) echo "invalid"&&exit;; +esac + +echo Step : 10$fromStepCount : Adding the changes to git +git add .&&echo "DONE" + +echo Step : 11$fromStepCount : Commit the new snapshot version to git + +git commit -m "Released "$nextVersion"-SNAPSHOT"&&echo "DONE" + +echo Step : 12$fromStepCount : Push to git +git push origin HEAD&&echo "DONE" + + +echo Step : 13$fromStepCount : Deploy the new snapshot to Maven repository +cd $pomParentDir +mvn clean deploy&&echo "DONE" +cd $currentDir + +echo "RELEASE OF NEW VERSION $currentVersion WAS JUST FINISHED" + +echo "NOW UPDATE DATA IN OCTAGON." + +echo "EXITING SCRIPT" + +gitk --all diff --git a/test.sh b/test.sh new file mode 100755 index 0000000..11c7dd2 --- /dev/null +++ b/test.sh @@ -0,0 +1,15 @@ +./build.sh&& \ +cd ./db-migration-core/target&& \ +java \ +-cp "db-migration-core-0.0.0-SNAPSHOT-jar-with-dependencies.jar:../../db-migration-test-jar/target/db-migration-test-jar-0.0.0-SNAPSHOT.jar" \ +--module-path "db-migration-core-0.0.0-SNAPSHOT-jar-with-dependencies.jar:../../db-migration-test-jar/target/db-migration-test-jar-0.0.0-SNAPSHOT.jar" \ +org.nanoboot.dbmigration.core.main.DBMigration \ +migrate \ +-datasource.jdbc-url=jdbc:sqlite:/home/robertvokac/Desktop/test.sqlite3 \ +-name=test -sql-dialect=sqlite \ +-sql-migrations-directory=/home/robertvokac/Desktop/testDev/ \ +-installed-by=robertvokac \ +-sql-dialect-impl-class=org.nanoboot.dbmigration.core.persistence.impl.sqlite.DBMigrationPersistenceSqliteImpl \ +&&cd ../.. + +#org.nanoboot.dbmigration.test.jar.DBMigrationTestJarDummyClass