turntables 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.document +3 -0
- data/.gitignore +6 -0
- data/.rspec +1 -0
- data/.travis.yml +6 -0
- data/.yardopts +1 -0
- data/ChangeLog.rdoc +10 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +141 -0
- data/Rakefile +33 -0
- data/bin/turntables +12 -0
- data/lib/turntables/constants/repository_constants.rb +6 -0
- data/lib/turntables/db_registry.rb +83 -0
- data/lib/turntables/repository.rb +148 -0
- data/lib/turntables/sql_modules/db_registry_sql.rb +7 -0
- data/lib/turntables/sql_modules/version_history_sql.rb +30 -0
- data/lib/turntables/transaction.rb +39 -0
- data/lib/turntables/turntable.rb +40 -0
- data/lib/turntables/turntable_exception.rb +7 -0
- data/lib/turntables/version.rb +4 -0
- data/lib/turntables/version_history.rb +90 -0
- data/lib/turntables.rb +2 -0
- data/spec/data/locations/.gitkeep +0 -0
- data/spec/data/locations/herp.db +0 -0
- data/spec/data/locations/loc1/.gitkeep +0 -0
- data/spec/data/malformed-dir/malformed.txt +1 -0
- data/spec/data/sql-just-monolithic/mono/1.sql +6 -0
- data/spec/data/sql-just-monolithic/seq/.gitkeep +0 -0
- data/spec/data/sql-just-sequential/mono/.gitkeep +0 -0
- data/spec/data/sql-just-sequential/seq/1.sql +6 -0
- data/spec/data/sql-just-sequential/seq/2.sql +7 -0
- data/spec/data/sql-just-sequential/seq/3.sql +9 -0
- data/spec/data/sql-seq-and-mono/mono/3.sql +24 -0
- data/spec/data/sql-seq-and-mono/seq/1.sql +6 -0
- data/spec/data/sql-seq-and-mono/seq/2.sql +7 -0
- data/spec/data/sql-seq-and-mono/seq/3.sql +9 -0
- data/spec/db_registry_sql_spec.rb +9 -0
- data/spec/repository_constants_spec.rb +13 -0
- data/spec/repository_spec.rb +39 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/turntable_exception_spec.rb +16 -0
- data/spec/turntable_spec.rb +71 -0
- data/spec/turntables_spec.rb +8 -0
- data/spec/version_history_spec.rb +55 -0
- data/spec/version_history_sql_spec.rb +31 -0
- data/turntables.gemspec +26 -0
- metadata +184 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f3b7cb827f0bb39e3cc31e2ead6a8d271e3068bf
|
4
|
+
data.tar.gz: bd4970ab7927b33a741e17b331056d03b81e388d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 09104fc43b8e05ca2a45798b0d3742c3f70189e95cfcbfa4779e2dd8ed42b18b49b4a2e9ffe03055133523b53dff4b9d81f258048ad15eadd8986753fd72725e
|
7
|
+
data.tar.gz: 32404ef39e95bb8dd4a61e1f1faa5add76b315b9a9607c146615e29b78a9fb8adb525f795e3145d793dd9916ff6fc7d030236e39afbcffb3d4f2d3af0aa619ad
|
data/.document
ADDED
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour --format documentation
|
data/.travis.yml
ADDED
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--markup rdoc --title "turntables Documentation" --protected
|
data/ChangeLog.rdoc
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
=== 1.0.0 / 2013-07-03
|
2
|
+
|
3
|
+
* Initial release:
|
4
|
+
* Can create db versioning with sequential transactions
|
5
|
+
* Can create db versioning with monolithic transactions
|
6
|
+
* Can detect malformed dirs / repos of said sql
|
7
|
+
|
8
|
+
* TODO
|
9
|
+
* Want to have a way to set the database name
|
10
|
+
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2013 psyomn
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
= turntables {<img src="https://codeclimate.com/github/psyomn/turntables.png" />}[https://codeclimate.com/github/psyomn/turntables] {<img src="https://travis-ci.org/psyomn/turntables.png?branch=master" alt="Build Status" />}[https://travis-ci.org/psyomn/turntables]
|
2
|
+
|
3
|
+
* {Source}[http://github.com/psyomn/turntables]
|
4
|
+
* {Homepage}[https://rubygems.org/gems/turntables]
|
5
|
+
* {Documentation}[http://rubydoc.info/gems/turntables/frames]
|
6
|
+
|
7
|
+
== Description
|
8
|
+
|
9
|
+
This is not really ready, but putting it out there because I actually need it
|
10
|
+
for something else I'm working on. If you can give a hand it will be very
|
11
|
+
appreciated (contact me).
|
12
|
+
|
13
|
+
== Features
|
14
|
+
|
15
|
+
== Examples
|
16
|
+
This is a simple tutorial on how to invoke the database manager.
|
17
|
+
|
18
|
+
You need a directory structure like this:
|
19
|
+
|
20
|
+
.
|
21
|
+
|-- main.rb
|
22
|
+
`-- sql
|
23
|
+
|-- mono
|
24
|
+
`-- seq
|
25
|
+
|-- 1.sql
|
26
|
+
|-- 2.sql
|
27
|
+
|-- 3.sql
|
28
|
+
`-- 4.sql
|
29
|
+
|
30
|
+
The sql files can be like this for example. The comments that are prepended
|
31
|
+
with '--$' are inserted in the version history table within the table manager
|
32
|
+
so that if someone needs to diagnose issues on the long run, there are the
|
33
|
+
comments there at least (along with a version, and date field).
|
34
|
+
|
35
|
+
1.sql:
|
36
|
+
|
37
|
+
--$ First version will be created with this. The comments to be added in the
|
38
|
+
--$ versions history table can be prepended with the '$' sign in order for you
|
39
|
+
--$ specify comments (if needed). It's here if you want it.
|
40
|
+
-- This is an example file to show how the turntables gem could work maybe
|
41
|
+
-- with people. and stuff.
|
42
|
+
-- This SQL file adds the person, and work_descriptions entities to the
|
43
|
+
-- database.
|
44
|
+
CREATE TABLE persons (
|
45
|
+
id integer primary key autoincrement,
|
46
|
+
name varchar(50),
|
47
|
+
surname varchar(50),
|
48
|
+
age integer
|
49
|
+
);
|
50
|
+
|
51
|
+
CREATE TABLE work_descriptions (
|
52
|
+
id integer primary key autoincrement,
|
53
|
+
description text
|
54
|
+
);
|
55
|
+
|
56
|
+
2.sql:
|
57
|
+
|
58
|
+
--$ Bump to version 2. This is starting to look good!
|
59
|
+
-- And this is for the second revision of the database.
|
60
|
+
|
61
|
+
CREATE TABLE inventory (
|
62
|
+
id integer primary key autoincrement,
|
63
|
+
description text
|
64
|
+
);
|
65
|
+
|
66
|
+
3.sql:
|
67
|
+
|
68
|
+
--$ We did a mistake. We forgot to add a field to the persons table. The extra
|
69
|
+
--$ field to be added is the DOB.
|
70
|
+
ALTER TABLE persons ADD COLUMN dob BIGINT;
|
71
|
+
|
72
|
+
4.sql:
|
73
|
+
|
74
|
+
--$ This table is added because now the system requires accounts as well.
|
75
|
+
--$ Sat Jul 13 21:45:40 EDT 2013
|
76
|
+
-- Table to create accounts for people.
|
77
|
+
CREATE TABLE accounts (
|
78
|
+
balance float,
|
79
|
+
owner_id integer,
|
80
|
+
FOREIGN KEY(owner_id) references persons(id)
|
81
|
+
);
|
82
|
+
|
83
|
+
main.rb should be like this:
|
84
|
+
|
85
|
+
require 'turntables'
|
86
|
+
|
87
|
+
include Turntables
|
88
|
+
|
89
|
+
puts "This is to test the library and proof of concept of turntables"
|
90
|
+
|
91
|
+
# Ideal way of calling this library
|
92
|
+
turntable = Turntable.new
|
93
|
+
|
94
|
+
# sql is a directory containing two subdirs: seq, mono
|
95
|
+
# seq contains sequential transactions
|
96
|
+
# mono contains monolithic transactions
|
97
|
+
turntable.register('sql')
|
98
|
+
turntable.make!
|
99
|
+
|
100
|
+
# Note: There should not be any other calls to the library. We give it the
|
101
|
+
# sql repository location, and then it's the responsibility of Turntables to
|
102
|
+
# decide whether to take action or not.
|
103
|
+
|
104
|
+
If you require that the database be made at a specified location, you should use
|
105
|
+
the method `make_at!(location)`. To do this, just do what the above code does
|
106
|
+
until `make!`. Then you need to call `make_at!` in the following way:
|
107
|
+
|
108
|
+
turntable.make_at!("path/to/database.db")
|
109
|
+
|
110
|
+
Right now versions should be marked as the filename. Try to have intergers as
|
111
|
+
versions, to avoid odd behaviour. So in this case versions {1,2,3} would
|
112
|
+
respectively be in file form {1.sql, 2.sql, 3.sql}.
|
113
|
+
|
114
|
+
The monolithic transactions should be a combinations of all the versions, up to
|
115
|
+
the one it denotes. In other words, version 4 would be the combination of all
|
116
|
+
previous ones including itself {1.sql, 2.sql, 3.sql, 4.sql}.
|
117
|
+
|
118
|
+
== Requirements
|
119
|
+
|
120
|
+
* I've tested this with Ruby Versions = {2.0, 1.9.3}, though you should not
|
121
|
+
really have any issues in theory.
|
122
|
+
|
123
|
+
* SQLite3 gem
|
124
|
+
|
125
|
+
== Install
|
126
|
+
|
127
|
+
$ gem install turntables
|
128
|
+
|
129
|
+
== Synopsis
|
130
|
+
|
131
|
+
$ turntables
|
132
|
+
|
133
|
+
== Copyright
|
134
|
+
|
135
|
+
Copyright (c) 2013 psyomn
|
136
|
+
|
137
|
+
== License
|
138
|
+
|
139
|
+
License is MIT regardless what you may see or find elsewhere; I might have not
|
140
|
+
changed it due to lack of time.
|
141
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'bundler'
|
7
|
+
rescue LoadError => e
|
8
|
+
warn e.message
|
9
|
+
warn "Run `gem install bundler` to install Bundler."
|
10
|
+
exit -1
|
11
|
+
end
|
12
|
+
|
13
|
+
begin
|
14
|
+
Bundler.setup(:development)
|
15
|
+
rescue Bundler::BundlerError => e
|
16
|
+
warn e.message
|
17
|
+
warn "Run `bundle install` to install missing gems."
|
18
|
+
exit e.status_code
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'rake'
|
22
|
+
|
23
|
+
require 'rspec/core/rake_task'
|
24
|
+
RSpec::Core::RakeTask.new
|
25
|
+
|
26
|
+
task :test => :spec
|
27
|
+
task :default => :spec
|
28
|
+
|
29
|
+
require "bundler/gem_tasks"
|
30
|
+
|
31
|
+
require 'yard'
|
32
|
+
YARD::Rake::YardocTask.new
|
33
|
+
task :doc => :yard
|
data/bin/turntables
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'sqlite3'
|
2
|
+
require 'singleton'
|
3
|
+
|
4
|
+
require 'turntables/sql_modules/db_registry_sql'
|
5
|
+
|
6
|
+
module Turntables
|
7
|
+
# Database Registry pattern that connects to an sqlite 3 database.
|
8
|
+
# @author Simon Symeonidis
|
9
|
+
class DbRegistry
|
10
|
+
include Singleton
|
11
|
+
include DbRegistrySql
|
12
|
+
|
13
|
+
# Init with default db name
|
14
|
+
# @param dbname is the name of the database is if it not specified
|
15
|
+
# TODO we need to be able to set this somehow differently - applications
|
16
|
+
# might require to name their database with their own specific name.
|
17
|
+
def initialize(dbname="default.db")
|
18
|
+
@handle = SQLite3::Database.new(dbname)
|
19
|
+
@name = dbname
|
20
|
+
end
|
21
|
+
|
22
|
+
# Execute (any sort) of sql
|
23
|
+
# @param sql is the multiple arguments of the function to execute. Usually
|
24
|
+
# you should give it first the sql you want that is to be prepared. Then
|
25
|
+
# you specify the variables to be set in the query, in the right order.
|
26
|
+
# @example Simple usage
|
27
|
+
# sql = "INSERT INTO person (name, surname) values (?,?)"
|
28
|
+
# DbRegistry.instance.execute(sql,"jon","doe")
|
29
|
+
# @return sql data
|
30
|
+
def execute(*sql)
|
31
|
+
@handle.execute(*sql)
|
32
|
+
rescue => ex
|
33
|
+
puts ex.message
|
34
|
+
puts ex.backtrace
|
35
|
+
puts "Offending sql: "
|
36
|
+
puts sql
|
37
|
+
end
|
38
|
+
|
39
|
+
# For special queries that may contain multiple statements. For example a
|
40
|
+
# query that contains first a 'create table' query, and then some inserts to
|
41
|
+
# poppulate that table. Ideally this should be used in order to create the
|
42
|
+
# tables in sequence.
|
43
|
+
# @param sql is the sql that contains multiple statements
|
44
|
+
def execute_batch(sql)
|
45
|
+
@handle.execute_batch(sql)
|
46
|
+
rescue => ex
|
47
|
+
puts ex.message
|
48
|
+
puts ex.backtrace
|
49
|
+
puts "Offending sql: "
|
50
|
+
puts sql
|
51
|
+
end
|
52
|
+
|
53
|
+
# Check if a table exists in the database
|
54
|
+
# @param name is the name of the table to check if exists
|
55
|
+
# @return true if table exists, false if not
|
56
|
+
def table_exists?(name)
|
57
|
+
val = @handle.execute(ExistsSql, "table", name)
|
58
|
+
1 == val.flatten[0]
|
59
|
+
end
|
60
|
+
|
61
|
+
# Close the current database.
|
62
|
+
# @warn This is mainly here for the rspec testing, and should not be used
|
63
|
+
# unless you really know what you're doing.
|
64
|
+
def close!
|
65
|
+
@handle.close unless @handle.closed?
|
66
|
+
end
|
67
|
+
|
68
|
+
# Open the database, with the name given previously
|
69
|
+
# @warn This is mainly here for the rspec testing, and should not be used
|
70
|
+
# unless you really know what you're doing.
|
71
|
+
def open!
|
72
|
+
@handle = SQLite3::Database.new(@name) if @handle.closed?
|
73
|
+
end
|
74
|
+
|
75
|
+
# The database name
|
76
|
+
attr_accessor :name
|
77
|
+
|
78
|
+
private
|
79
|
+
# Other classes should not use the database handle directly
|
80
|
+
attr :handle
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
@@ -0,0 +1,148 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
# lib
|
4
|
+
require 'turntables/transaction'
|
5
|
+
require 'turntables/version_history'
|
6
|
+
require 'turntables/db_registry'
|
7
|
+
require 'turntables/sql_modules/version_history_sql'
|
8
|
+
require 'turntables/constants/repository_constants'
|
9
|
+
|
10
|
+
module Turntables
|
11
|
+
# @author Simon Symeonidis
|
12
|
+
# A turntables repository. This class is responsible for handling the
|
13
|
+
# versioning. This includes tasks such as checking database availability,
|
14
|
+
# and pulling up the version history table and modifying where needed (for
|
15
|
+
# example when completing a transaction, recording the date, the new version,
|
16
|
+
# and comments about said transaction).
|
17
|
+
class Repository
|
18
|
+
include RepositoryConstants
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
@transactions = Array.new
|
22
|
+
@monolithics = Array.new
|
23
|
+
end
|
24
|
+
|
25
|
+
# @param location is the location of the sql repository for now (a directory
|
26
|
+
# for now).
|
27
|
+
def register(location)
|
28
|
+
@relative_dir = location
|
29
|
+
@sequential_dir = "#{@relative_dir}/#{SeqDir}/"
|
30
|
+
@monolithic_dir = "#{@relative_dir}/#{MonoDir}/"
|
31
|
+
|
32
|
+
# Initialize the transactions
|
33
|
+
init_sequential_transactions!
|
34
|
+
init_monolithic_transactions!
|
35
|
+
end
|
36
|
+
|
37
|
+
# Function to call in order to make the database.
|
38
|
+
#
|
39
|
+
# TODO: Here, it should detect in what state the current database is in, and
|
40
|
+
# go from there. In other words, whether it can skip sequential database
|
41
|
+
# transactions by loading a monolithic one to exclude previous transactions.
|
42
|
+
def make!
|
43
|
+
select_transactions!
|
44
|
+
@transactions.each do |transaction|
|
45
|
+
vh = VersionHistory.new(transaction.version, transaction.comment)
|
46
|
+
VersionHistory.insert(vh)
|
47
|
+
DbRegistry.instance.execute_batch(transaction.data)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Check to see if the directory structure is malformed.
|
52
|
+
# @return true if the directory structure is malformed
|
53
|
+
def malformed?
|
54
|
+
abs_seq = File.expand_path(@sequential_dir)
|
55
|
+
abs_mon = File.expand_path(@monolithic_dir)
|
56
|
+
!(File.exists?(abs_seq) && File.exists?(abs_mon))
|
57
|
+
end
|
58
|
+
|
59
|
+
attr_accessor :sequential_dir
|
60
|
+
attr_accessor :monolithic_dir
|
61
|
+
attr_accessor :relative_dir
|
62
|
+
# Array<Turntables::Transaction>
|
63
|
+
attr_accessor :transactions
|
64
|
+
# Array<Turntables::Transaction>
|
65
|
+
attr_accessor :monolithics
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
# Depending on what has been done before, we need to choose the proper
|
70
|
+
# transactions.
|
71
|
+
# TODO: This probably can be done cleaner
|
72
|
+
def select_transactions!
|
73
|
+
check = VersionHistory.check
|
74
|
+
if check == :fresh
|
75
|
+
# Fresh db means, we create the version history table
|
76
|
+
prepend_monolithic_transactions!
|
77
|
+
VersionHistory.pull_up!
|
78
|
+
else
|
79
|
+
last_version = VersionHistory.find_last.version
|
80
|
+
@transactions.select!{|tr| tr.version > last_version}
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# This checks to see if any monolithic transactions exist, which can
|
85
|
+
# eliminate previous sequential transactions.
|
86
|
+
def prepend_monolithic_transactions!
|
87
|
+
max = @monolithics.max_by &:version
|
88
|
+
unless max.nil?
|
89
|
+
@transactions.select!{|tr| tr.version > max.version}
|
90
|
+
@transactions = @transactions.unshift(max)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Find all the transactions that are to be processed sequentially
|
95
|
+
# @return nil
|
96
|
+
def init_sequential_transactions!
|
97
|
+
init_generic_transactions(sequential_files, @transactions)
|
98
|
+
end
|
99
|
+
|
100
|
+
# Find all the transactions that are to be processed only once
|
101
|
+
# @return nil
|
102
|
+
def init_monolithic_transactions!
|
103
|
+
init_generic_transactions(monolithic_files, @monolithics)
|
104
|
+
end
|
105
|
+
|
106
|
+
# this is a generic transaction reader
|
107
|
+
# return nil
|
108
|
+
def init_generic_transactions(file_list, transaction_holder)
|
109
|
+
file_list.each do |path|
|
110
|
+
data = File.open(path).read
|
111
|
+
filename = path.split(/\//).last
|
112
|
+
transaction_holder.push Transaction.new(data,filename)
|
113
|
+
end
|
114
|
+
nil
|
115
|
+
end
|
116
|
+
|
117
|
+
# Get the sequential transactional files
|
118
|
+
def sequential_files
|
119
|
+
get_files_in_dir(@sequential_dir)
|
120
|
+
end
|
121
|
+
|
122
|
+
# Get the monolithic transactional files
|
123
|
+
def monolithic_files
|
124
|
+
get_files_in_dir(@monolithic_dir)
|
125
|
+
end
|
126
|
+
|
127
|
+
# Return the files that are in the given directory
|
128
|
+
# @param path is the path to look for files in the directory
|
129
|
+
# @return Array<String> of files sorted by stringnum_comparison predicate
|
130
|
+
def get_files_in_dir(path)
|
131
|
+
Dir["#{path}*"].sort!{|e1,e2| stringnum_comparison(e1,e2)}
|
132
|
+
end
|
133
|
+
|
134
|
+
# Compare two strings with each other by extracting the digits
|
135
|
+
def stringnum_comparison(a,b)
|
136
|
+
extract_digits(a) <=> extract_digits(b)
|
137
|
+
end
|
138
|
+
|
139
|
+
# Extract the numbers from the string, and convert to Fixnum
|
140
|
+
# @param string is the string to extract the numbers from
|
141
|
+
# @return the number that was found in the string
|
142
|
+
def extract_digits(string)
|
143
|
+
string.gsub(/\D/,'').to_i
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Turntables
|
2
|
+
# @author Simon Symeonidis
|
3
|
+
# Some static information factored out to avoid class variables, and to
|
4
|
+
# separate concerns.
|
5
|
+
module VersionHistorySql
|
6
|
+
# Table name of this guy
|
7
|
+
TableName = "version_histories"
|
8
|
+
|
9
|
+
# Table schema for the version history table.
|
10
|
+
Create = "CREATE TABLE #{TableName} ("\
|
11
|
+
"id INTEGER PRIMARY KEY AUTOINCREMENT, "\
|
12
|
+
"version BIGINT, "\
|
13
|
+
"date BIGINT, "\
|
14
|
+
"comment TEXT)"
|
15
|
+
|
16
|
+
# Select last inserted transaction
|
17
|
+
SelectLast = "SELECT * FROM #{TableName} "\
|
18
|
+
" WHERE id=(SELECT MAX(id) FROM #{TableName});"
|
19
|
+
|
20
|
+
# Select a record by id
|
21
|
+
SelectById = "SELECT * FROM #{TableName} WHERE id=?"
|
22
|
+
|
23
|
+
# Select all the records
|
24
|
+
SelectAll = "SELECT * FROM #{TableName}"
|
25
|
+
|
26
|
+
# Sql to insert a version history into the table
|
27
|
+
Insert = "INSERT INTO #{TableName} (version,date,comment)"\
|
28
|
+
" values (?,?,?)"
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Turntables
|
2
|
+
# @author Simon Symeonidis
|
3
|
+
# @date Wed Jul 10 19:51:42 EDT 2013
|
4
|
+
# This class takes care of a single transaction
|
5
|
+
class Transaction
|
6
|
+
|
7
|
+
# Initialize this object with the contents of the sql file
|
8
|
+
# @param sql_file_contents are the contents of the given sql file
|
9
|
+
# @param filename is the filename of the given sql file. We use the filenames
|
10
|
+
# for the version that it is supposed to upgrade to.
|
11
|
+
def initialize(sql_file_contents,filename)
|
12
|
+
# Select only the lines that begin with '--$'
|
13
|
+
@comment = sql_file_contents.lines.select{|el| el.match(/--\$/)}.join
|
14
|
+
@comment.gsub!(/--\$/, '')
|
15
|
+
@version = filename.to_i
|
16
|
+
@data = sql_file_contents
|
17
|
+
end
|
18
|
+
|
19
|
+
# The version should be obtained from the file name of the respective sql
|
20
|
+
# file.
|
21
|
+
attr_accessor :version
|
22
|
+
|
23
|
+
# The comment should be parsed out from the respective sql file. We want to
|
24
|
+
# keep the comments in the sql file to keep things organized. We do not want
|
25
|
+
# to alter the sql language to fit our needs. Therefore we just require the
|
26
|
+
# user to comment lines as '--$ my comment here' in order to parse them out
|
27
|
+
# @example How to write comments that are to be parsed
|
28
|
+
# --$ author jon doe
|
29
|
+
# --$ This sql file will update the schema to version 1.2
|
30
|
+
# --$ You should note this and that
|
31
|
+
# -- This commen line would be ignored
|
32
|
+
#
|
33
|
+
# CREATE TABLE accounts ( ... )
|
34
|
+
attr_accessor :comment
|
35
|
+
|
36
|
+
# The sql information to be passed on to the db registry
|
37
|
+
attr_accessor :data
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'turntables/db_registry'
|
2
|
+
require 'turntables/repository'
|
3
|
+
require 'turntables/turntable_exception'
|
4
|
+
|
5
|
+
module Turntables
|
6
|
+
# @author Simon Symeonidis
|
7
|
+
# The facade controller to the rest of this library.
|
8
|
+
class Turntable
|
9
|
+
# Default constructor, that initializes some standard parameters
|
10
|
+
def initialize
|
11
|
+
@revisions = Array.new
|
12
|
+
@repository = Repository.new
|
13
|
+
end
|
14
|
+
|
15
|
+
# Register a revision that needs to be processed later
|
16
|
+
# @param repository_root_path is the root path to all the sql.
|
17
|
+
def register(repository_root_path)
|
18
|
+
@repository.register(repository_root_path)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Make the repository at a specific location instead of default.
|
22
|
+
def make_at!(location)
|
23
|
+
DbRegistry.instance.close!
|
24
|
+
DbRegistry.instance.name = location
|
25
|
+
DbRegistry.instance.open!
|
26
|
+
make!
|
27
|
+
end
|
28
|
+
|
29
|
+
# Create the tables by going through each revision
|
30
|
+
def make!
|
31
|
+
if @repository.malformed?
|
32
|
+
raise TurntableException, "The directory structure is malformed."
|
33
|
+
else
|
34
|
+
@repository.make!
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
attr_accessor :repository
|
39
|
+
end
|
40
|
+
end
|