Skip to content

Commit ed45c82

Browse files
committed
Changed inputs to not have _data attached to them. Changed connection to database to be a contextmanager. Updated config to have a base of connections instead of sql. Made all necessary updates to readme and tests.
1 parent e119614 commit ed45c82

17 files changed

+132
-141
lines changed

README.md

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ It can contain an array of one or more sets of SQL connection parameters, like t
4040

4141
``` yaml
4242
---
43-
sql:
43+
connections:
4444
postgresql:
4545
host: postgresql_db.domain.tld
4646
@@ -75,7 +75,9 @@ Alternatively, when running an action, you can pass in the host, username, passw
7575

7676
**Note** : When modifying the configuration in `/opt/stackstorm/configs/` please remember to tell StackStorm to load these new values by running `st2ctl reload --register-configs`
7777

78-
# Actions
78+
# Usage
79+
80+
## Actions
7981

8082
| Action | Description |
8183
|--------|-------------|
@@ -84,3 +86,20 @@ Alternatively, when running an action, you can pass in the host, username, passw
8486
| insert_bulk | Bulk insert data into a database table. Insert data is passed as an array of objects. |
8587
| update | Update data in a database table. |
8688
| delete | Delete data from a database table. |
89+
90+
## Where statements
91+
92+
The Update and Delete actions give the option to include where data into the query. This only works for AND statements.
93+
94+
Example:
95+
```
96+
where = {
97+
'column_1': 'value_1',
98+
'column_2': 'value_2'
99+
}
100+
101+
Produces the statement:
102+
WHERE column_1 == 'value_1' AND column_2 == 'value_2'
103+
```
104+
105+
For more complicated queries please use the query action.

actions/delete.py

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,29 +17,24 @@ def run(self, **kwargs):
1717
"""
1818
kwargs_dict = dict(kwargs)
1919

20-
where_dict = self.get_del_arg('where_data', kwargs_dict, True)
21-
table = self.get_del_arg('table', kwargs_dict, True)
20+
where_dict = self.get_del_arg('where', kwargs_dict)
21+
table = self.get_del_arg('table', kwargs_dict)
2222

23-
# Get the connection details from either config or from action params
24-
connection_details = self.resolve_connection(kwargs_dict)
23+
with self.db_connection(kwargs_dict) as conn:
24+
# Get the SQL table
25+
sql_table = sqlalchemy.Table(table,
26+
self.meta,
27+
autoload=True,
28+
autoload_with=self.engine)
2529

26-
# Connect to the Database
27-
self.connect_to_db(connection_details)
30+
# Intantiate delete object
31+
delete = sql_table.delete() # pylint: disable-msg=no-value-for-parameter
2832

29-
# Get the SQL table
30-
sql_table = sqlalchemy.Table(table, self.meta, autoload=True, autoload_with=self.engine)
33+
# Generate Where Statement
34+
if where_dict:
35+
delete, where_dict = self.generate_where_clause(sql_table, delete, where_dict)
3136

32-
# Intantiate delete object
33-
delete = sql_table.delete() # pylint: disable-msg=no-value-for-parameter
34-
35-
# Generate Where Statement
36-
if where_dict:
37-
delete, where_dict = self.generate_where_clause(sql_table, delete, where_dict)
38-
39-
# Execute query
40-
result = self.conn.execute(delete, where_dict)
41-
42-
# Disconnect from the database
43-
self.conn.close()
37+
# Execute query
38+
result = conn.execute(delete, where_dict)
4439

4540
return {'affected_rows': result.rowcount}

actions/delete.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
type: string
4848
description: "Database table to DELETE."
4949
required: true
50-
where_data:
50+
where:
5151
type: object
5252
description: >
5353
Dictionary of data to be used to create a WHERE clause for the DELETE statement

actions/generic_query.py

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,26 +16,19 @@ def run(self, **kwargs):
1616
"""
1717
kwargs_dict = dict(kwargs)
1818

19-
query = self.get_del_arg('query', kwargs_dict, True)
19+
query = self.get_del_arg('query', kwargs_dict)
2020

21-
# Get the connection details from either config or from action params
22-
connection_details = self.resolve_connection(kwargs_dict)
23-
24-
# Connect to the Database
25-
self.connect_to_db(connection_details)
26-
27-
# Execute the query
28-
query_result = self.conn.execute(query)
21+
with self.db_connection(kwargs_dict) as conn:
22+
# Execute the query
23+
query_result = conn.execute(query)
2924

3025
return_result = {'affected_rows': query_result.rowcount}
3126
if query_result.returns_rows:
3227
return_result = []
3328
all_results = query_result.fetchall()
3429
for row in all_results:
35-
# Rows are returned as tuples with keys. Convert that to a dictionary for return
30+
# Rows are returned as tuples with keys.
31+
# Convert that to a dictionary for return
3632
return_result.append(self.row_to_dict(row))
3733

38-
# Disconnect from the database
39-
self.conn.close()
40-
4134
return return_result

actions/insert.py

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,29 +17,21 @@ def run(self, **kwargs):
1717
"""
1818
kwargs_dict = dict(kwargs)
1919

20-
insert_data = self.get_del_arg('data', kwargs_dict, True)
21-
insert_table = self.get_del_arg('table', kwargs_dict, True)
20+
insert_data = self.get_del_arg('data', kwargs_dict)
21+
insert_table = self.get_del_arg('table', kwargs_dict)
2222

2323
if not isinstance(insert_data, list):
2424
insert_data = [insert_data]
2525

26-
# Get the connection details from either config or from action params
27-
connection_details = self.resolve_connection(kwargs_dict)
26+
with self.db_connection(kwargs_dict) as conn:
27+
# Get the Table to insert data into
28+
sql_table = sqlalchemy.Table(insert_table,
29+
self.meta,
30+
autoload=True,
31+
autoload_with=self.engine)
2832

29-
# Connect to the Database
30-
self.connect_to_db(connection_details)
31-
32-
# Get the Table to insert data into
33-
sql_table = sqlalchemy.Table(insert_table,
34-
self.meta,
35-
autoload=True,
36-
autoload_with=self.engine)
37-
38-
# Execute the insert query
39-
self.conn.execute(sql_table.insert(), # pylint: disable-msg=no-value-for-parameter
40-
insert_data)
41-
42-
# Disconnect from the database
43-
self.conn.close()
33+
# Execute the insert query
34+
conn.execute(sql_table.insert(), # pylint: disable-msg=no-value-for-parameter
35+
insert_data)
4436

4537
return True

actions/lib/base_action.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from sqlalchemy.engine.url import URL
44
import decimal
55
import datetime
6+
from contextlib import contextmanager
67

78
# (key, required, default)
89
CONFIG_CONNECTION_KEYS = [('host', False, ""),
@@ -97,17 +98,25 @@ def generate_values(self, sql_obj, data_dict):
9798

9899
return sql_obj
99100

100-
def connect_to_db(self, connection):
101+
@contextmanager
102+
def db_connection(self, kwargs_dict):
101103
"""Connect to the database and instantiate necessary methods to be used
102104
later.
103105
"""
106+
# Get the connection details from either config or from action params
107+
connection = self.resolve_connection(kwargs_dict)
108+
109+
# Format the connection string
104110
database_connection_string = URL(**connection)
105111

106112
self.engine = sqlalchemy.create_engine(database_connection_string, echo=False)
107-
self.conn = self.engine.connect()
108113
self.meta = sqlalchemy.MetaData()
114+
conn = self.engine.connect()
109115

110-
return True
116+
try:
117+
yield conn
118+
finally:
119+
conn.close()
111120

112121
def validate_connection(self, connection, connection_name):
113122
"""Ensures that all required parameters are in the connection. If a
@@ -144,7 +153,7 @@ def resolve_connection(self, kwargs_dict):
144153
connection_name = self.get_del_arg('connection', kwargs_dict, True)
145154
config_connection = None
146155
if connection_name:
147-
config_connection = self.config['sql'].get(connection_name)
156+
config_connection = self.config['connections'].get(connection_name)
148157
if not config_connection:
149158
raise KeyError("config.yaml missing connection: sql:{0}"
150159
.format(connection_name))

actions/update.py

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,35 +17,30 @@ def run(self, **kwargs):
1717
"""
1818
kwargs_dict = dict(kwargs)
1919

20-
where_dict = self.get_del_arg('where_data', kwargs_dict, True)
21-
update_dict = self.get_del_arg('update_data', kwargs_dict, True)
22-
table = self.get_del_arg('table', kwargs_dict, True)
20+
where_dict = self.get_del_arg('where', kwargs_dict)
21+
update_dict = self.get_del_arg('update', kwargs_dict)
22+
table = self.get_del_arg('table', kwargs_dict)
2323

24-
# Get the connection details from either config or from action params
25-
connection_details = self.resolve_connection(kwargs_dict)
24+
with self.db_connection(kwargs_dict) as conn:
25+
# Get the SQL table
26+
sql_table = sqlalchemy.Table(table,
27+
self.meta,
28+
autoload=True,
29+
autoload_with=self.engine)
2630

27-
# Connect to the Database
28-
self.connect_to_db(connection_details)
31+
# Intantiate update object
32+
updates = sql_table.update() # pylint: disable-msg=no-value-for-parameter
2933

30-
# Get the SQL table
31-
sql_table = sqlalchemy.Table(table, self.meta, autoload=True, autoload_with=self.engine)
34+
# Generate Where Statement
35+
if where_dict:
36+
updates, where_dict = self.generate_where_clause(sql_table, updates, where_dict)
3237

33-
# Intantiate update object
34-
updates = sql_table.update() # pylint: disable-msg=no-value-for-parameter
38+
updates = self.generate_values(updates, update_dict)
3539

36-
# Generate Where Statement
37-
if where_dict:
38-
updates, where_dict = self.generate_where_clause(sql_table, updates, where_dict)
40+
# Combine Dictionaries
41+
query_dict = self.merge_dicts([where_dict, update_dict])
3942

40-
updates = self.generate_values(updates, update_dict)
41-
42-
# Combine Dictionaries
43-
query_dict = self.merge_dicts([where_dict, update_dict])
44-
45-
# Execute query
46-
result = self.conn.execute(updates, query_dict)
47-
48-
# Disconnect from the database
49-
self.conn.close()
43+
# Execute query
44+
result = conn.execute(updates, query_dict)
5045

5146
return {'affected_rows': result.rowcount}

actions/update.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
type: string
4848
description: "Database table to UPDATE."
4949
required: true
50-
where_data:
50+
where:
5151
type: object
5252
description: >
5353
Dictionary of data to be used to create a WHERE clause for the UPDATE statement
@@ -59,7 +59,7 @@
5959
}
6060
required: false
6161
default: {}
62-
update_data:
62+
update:
6363
type: object
6464
description: >
6565
Dictionary of data to be used to as Values to update for the UPDATE statement

config.schema.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22

3-
sql:
3+
connections:
44
type: "object"
55
required: true
66
patternProperties:
@@ -44,4 +44,4 @@ connection:
4444
- firebird
4545
- sybase
4646
required: true
47-
additionalProperties: false
47+
additionalProperties: false

sql.yaml.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
sql:
2+
connections:
33
postgresql:
44
host: postgresql_db.domain.tld
55

0 commit comments

Comments
 (0)