Skip to content

Commit ce3bad1

Browse files
committed
Initial Commit
1 parent 21239f3 commit ce3bad1

File tree

4 files changed

+354
-8
lines changed

4 files changed

+354
-8
lines changed

HoneyCodeORM.template

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
import boto3
2+
3+
class {{classNameEditor}}:
4+
def __init__(self) -> object:
5+
self.tableid = "{{tableID}}"
6+
self.workbookid = "{{workbookID}}"
7+
self.tablename = "{{tableName}}"
8+
self.honeycode_client = boto3.client('honeycode')
9+
10+
#list all rows in the table
11+
def listAllRows(self):
12+
rowRet = []
13+
nextToken2 = ""
14+
response = self.honeycode_client.list_table_rows(
15+
workbookId=self.workbookid,
16+
tableId=self.tableid, maxResults=100)
17+
if "nextToken" in response:
18+
nextToken2 = response["nextToken"]
19+
for row in response["rows"]:
20+
rowRet.append(self.__convertRowOfHoneycodeDataToObject(row))
21+
while nextToken2:
22+
response = self.honeycode_client.list_table_rows(
23+
workbookId=self.workbookid,
24+
tableId=self.tableid, maxResults=100, nextToken=nextToken2)
25+
nextToken2 = ""
26+
if "nextToken" in response:
27+
nextToken2 = response["nextToken"]
28+
for row in response["rows"]:
29+
rowRet.append(self.__convertRowOfHoneycodeDataToObject(row))
30+
return rowRet
31+
32+
33+
#find rows with criteria
34+
def find(self, columnName, operator, value):
35+
searchVal = "=Filter("+self.tablename+",\""+self.tablename+"["+columnName+"]"+operator+"%\", \""+value+"\")"
36+
response = self.honeycode_client.query_table_rows(
37+
workbookId=self.workbookid,
38+
tableId=self.tableid,
39+
filterFormula={"formula": searchVal})
40+
retValue = []
41+
for row in response["rows"]:
42+
retValue.append(self.__convertRowOfHoneycodeDataToObject(row))
43+
return retValue
44+
45+
#Update one row
46+
def updateRow(self, o_row):
47+
response = self.honeycode_client.batch_update_table_rows(
48+
workbookId=self.workbookid,
49+
tableId=self.tableid,
50+
rowsToUpdate=
51+
self.__convertRowsOfObjectsToHoneyCodeUpdateRows([o_row])
52+
)
53+
54+
#Update multipule rows
55+
def updateRows(self, o_rows):
56+
rows = self.__convertRowsOfObjectsToHoneyCodeUpdateRows(o_rows)
57+
for i in range(0, len(rows), 100):
58+
response = self.honeycode_client.batch_update_table_rows(
59+
workbookId=self.workbookid,
60+
tableId=self.tableid,
61+
rowsToUpdate=rows[i:i + 100]
62+
63+
)
64+
#takes a row or an id
65+
def deleteRow(self, o_row):
66+
response = self.honeycode_client.batch_delete_table_rows(
67+
workbookId=self.workbookid,
68+
tableId=self.tableid,
69+
rowIds=[o_row.rowId])
70+
71+
#deletes all rows in this table
72+
def deleteAllRows(self):
73+
rows = self.listAllRows()
74+
for i in range(0, len(rows), 100):
75+
response = self.honeycode_client.batch_delete_table_rows(
76+
workbookId=self.workbookid,
77+
tableId=self.tableid,
78+
rowIds=rows[i:i + 100]
79+
)
80+
81+
def batchSaveRows(self, o_rows):
82+
maxBatchSize = 100
83+
currentPage = 0
84+
85+
rows = self.__convertRowsOfObjectsToHoneyCodeRows(o_rows)
86+
while currentPage*maxBatchSize < len(rows):
87+
begin = currentPage * maxBatchSize
88+
end = (currentPage * maxBatchSize) + maxBatchSize
89+
if end > len(rows):
90+
end = len(rows)
91+
currentPage+=1
92+
response = self.honeycode_client.batch_create_table_rows(
93+
workbookId=self.workbookid,
94+
tableId=self.tableid,
95+
rowsToCreate=rows[begin:end])
96+
for batchid in response["createdRows"]:
97+
for row in o_rows:
98+
if row.batchid == batchid:
99+
row.rowId = response["createdRows"][batchid]
100+
101+
#convert honeycode row to object
102+
def __convertRowOfHoneycodeDataToObject(self, row):
103+
ar = {{classnameRow}}({{findDataFromColumn}}, row["rowId"])
104+
return ar
105+
106+
#convience function to convert objects to rows
107+
def __convertRowsOfObjectsToHoneyCodeRows(self, rows):
108+
insertableRows = []
109+
batchID = 0
110+
for row in rows:
111+
batchID += 1
112+
convertedRow = row.createInsertRowData("insert" + str(batchID))
113+
row.batchid = "insert" + str(batchID)
114+
insertableRows.append(convertedRow)
115+
return insertableRows
116+
117+
#convience function to convert objects to updates
118+
def __convertRowsOfObjectsToHoneyCodeUpdateRows(self, rows):
119+
insertableRows = []
120+
batchID = 0
121+
for row in rows:
122+
batchID += 1
123+
convertedRow = row.createUpdateRowData()
124+
insertableRows.append(convertedRow)
125+
return insertableRows
126+
127+
#Class For data
128+
class {{classnameRow}}:
129+
def __init__(self{{variableNamesParams}}, rowId=None) -> object:
130+
self.rowId = rowId
131+
self.batchid = ""
132+
{{variableNamesAlloc}}
133+
134+
def __repr__(self):
135+
return "{{classnameRow}}<" + str(self.rowId) + ">"
136+
137+
def __str__(self):
138+
return "{{classnameRow}}<" + {{printstatment}} + ">"
139+
140+
def save(self):
141+
iface = {{classNameEditor}}()
142+
if self.rowId:
143+
iface.updateRow(self)
144+
else:
145+
iface.batchSaveRows([self])
146+
147+
def delete(self):
148+
iface = {{classNameEditor}}()
149+
iface.deleteRow(self)
150+
self.rowId = ""
151+
152+
def createInsertRowData(self, batch_item_id):
153+
operation = "cellsToCreate"
154+
dictToAdd = {
155+
"batchItemId": batch_item_id,
156+
operation: {
157+
}
158+
}
159+
{{honeyCodeRowDefs}}
160+
return dictToAdd
161+
def createUpdateRowData(self):
162+
operation = "cellsToUpdate"
163+
dictToAdd = {
164+
"rowId": self.rowId,
165+
operation: {
166+
}
167+
}
168+
{{honeyCodeRowDefs}}
169+
return dictToAdd
170+
171+

HoneycodeORMBuilder.py

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance
4+
# with the License. A copy of the License is located at
5+
#
6+
# http://aws.amazon.com/apache2.0/
7+
#
8+
# or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
9+
# OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
10+
# and limitations under the License.
11+
import os
12+
13+
import boto3
14+
import jinja2
15+
import sys
16+
from pathlib import Path
17+
import re
18+
19+
class HoneycodeORMBuilder:
20+
def __init__(self, workbookid) -> object:
21+
self.workbookid = workbookid
22+
self.pythonvarnameregex = re.compile('[^a-zA-Z0-9]')
23+
self.honeycode_client = boto3.client('honeycode')
24+
Path("orm").mkdir(parents=True, exist_ok=True)
25+
dir = os.getcwd() + '/orm'
26+
for f in os.listdir(dir):
27+
os.remove(os.path.join(dir, f))
28+
29+
def buildORM(self):
30+
honeycodetabledec = self.honeycode_client.list_tables(
31+
workbookId=self.workbookid)
32+
for table in honeycodetabledec['tables']:
33+
tableName = table["tableName"]
34+
tableId = table["tableId"]
35+
templateLoader = jinja2.FileSystemLoader(searchpath="./")
36+
templateEnv = jinja2.Environment(loader=templateLoader)
37+
template = templateEnv.get_template("HoneyCodeORM.template")
38+
39+
honeycodecolumndec = self.honeycode_client.list_table_columns(
40+
workbookId=self.workbookid, tableId=tableId)
41+
printstatement = self.buildPrintStatement(honeycodecolumndec)
42+
outputText = template.render(classNameEditor=tableName + "BatchOperations",
43+
tableID=tableId,
44+
workbookID=self.workbookid,
45+
tableName=tableName,
46+
findDataFromColumn=self.buildConvert(honeycodecolumndec),
47+
classnameRow=tableName,
48+
printstatment = printstatement,
49+
variableNamesParams=self.buildParamsForTable(honeycodecolumndec),
50+
variableNamesAlloc=self.buildVarAllocForTable(honeycodecolumndec),
51+
honeyCodeRowDefs=self.buildInsertForTable(honeycodecolumndec) )
52+
text_file = open("orm/" + tableName + ".py", "w")
53+
text_file.write(outputText)
54+
text_file.close()
55+
56+
57+
def buildInsertForTable(self, response):
58+
tableDescript = response["tableColumns"]
59+
buildstuff = ""
60+
for tableColumn in tableDescript:
61+
buildstuff += ' ' + "if self." + self.pythonvarnameregex.sub('', tableColumn["tableColumnName"]).lower() + ":\n"
62+
buildstuff += ' dictToAdd[operation][' + '"' + tableColumn["tableColumnId"] + '"' + '] = {"fact": self.' + self.pythonvarnameregex.sub('', tableColumn["tableColumnName"]).lower() + "}\n"
63+
return buildstuff
64+
65+
def buildPrintStatement(self, response):
66+
tableDescript = response["tableColumns"]
67+
buildstuff = ""
68+
for tableColumn in tableDescript:
69+
buildstuff += ' "' + tableColumn["tableColumnName"] + '=" + str(self.' + self.pythonvarnameregex.sub('', tableColumn["tableColumnName"]).lower() + ') + "," +'
70+
return buildstuff[:len(buildstuff)-8]
71+
72+
def buildVarAllocForTable(self, response):
73+
tableDescript = response["tableColumns"]
74+
buildstuff = ""
75+
for tableColumn in tableDescript:
76+
buildstuff += ' self.' + self.pythonvarnameregex.sub('', tableColumn["tableColumnName"]).lower() + " = " + self.pythonvarnameregex.sub('', tableColumn["tableColumnName"]).lower() + '\n'
77+
return buildstuff
78+
79+
def buildConvert(self, response):
80+
tableDescript = response["tableColumns"]
81+
i = 0
82+
retVal = ""
83+
while i < len(tableDescript):
84+
retVal += 'row["cells"]['+str(i)+'].get("formattedValue"), '
85+
i+=1
86+
return retVal[:-2]
87+
88+
def buildParamsForTable(self, response):
89+
tableDescript = response["tableColumns"]
90+
params = ""
91+
for tableColumn in tableDescript:
92+
params = params + "," + self.pythonvarnameregex.sub('', tableColumn["tableColumnName"]).lower() + "=None"
93+
return params
94+
95+
def getTableIdByName(self, name):
96+
response = self.honeycode_client.list_tables(
97+
workbookId=self.workbookid)
98+
for table in response['tables']:
99+
if table["tableName"] == name:
100+
return table["tableId"]
101+
return ""
102+
103+
def main(workbookid):
104+
hcb = HoneycodeORMBuilder(workbookid)
105+
hcb.buildORM()
106+
107+
if __name__ == "__main__":
108+
if len(sys.argv) < 2:
109+
print("Please pass in workbook id")
110+
else:
111+
main(sys.argv[1])

README.md

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1-
## My Project
1+
# Honeycodeorm
22

3-
TODO: Fill this README out!
3+
Honeycode ORM provides an Object Relational Model for interaction with Honeycode workbooks. HoneycodeORMBuilder is the
4+
main file, pass in your workbook name, and a series of classes will be generated in the "orm" folder, one file per
5+
table in your Honeycode workbook. Each file has two classes, one for batch operation, and one that holds and object
6+
that represents a row in your table.
47

5-
Be sure to:
8+
## Documentation
69

7-
* Change the title in this README
8-
* Edit your repository description on GitHub
10+
Example Usage of builder:
11+
python HoneycodeORMBuilder.py <workbookid>
912

10-
## Security
11-
12-
See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information.
13+
Output in the ORM folder a list of files representing your tables
1314

1415
## License
1516

test_HoneycodeORMBuilder.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance
4+
# with the License. A copy of the License is located at
5+
#
6+
# http://aws.amazon.com/apache2.0/
7+
#
8+
# or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
9+
# OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
10+
# and limitations under the License.
11+
from unittest import TestCase, mock
12+
from unittest.mock import MagicMock
13+
import os, os.path
14+
from HoneycodeORMBuilder import HoneycodeORMBuilder
15+
16+
mock_list_tables_response = {
17+
'tables': [{'tableId': '00000000-0000-0000-0000-000000000001', 'tableName': 'test1'},
18+
{'tableId': '00000000-0000-0000-0000-000000000002', 'tableName': 'test2'},],
19+
}
20+
mock_list_columns_response = {
21+
'tableColumns': [
22+
{'tableColumnId': '00000000-0000-0000-0000-000000000006', 'tableColumnName': 'Parameter',
23+
'format': 'AUTO'},
24+
{'tableColumnId': '00000000-0000-0000-0000-000000000007', 'tableColumnName': 'Weight',
25+
'format': 'AUTO'},
26+
{'tableColumnId': '00000000-0000-0000-0000-000000000008', 'tableColumnName': 'Color', 'format': 'AUTO'},
27+
{'tableColumnId': '00000000-0000-0000-0000-000000000009', 'tableColumnName': 'Description',
28+
'format': 'AUTO'}]}
29+
class TestHoneycodeORMBuilder(TestCase):
30+
31+
@mock.patch("botocore.client")
32+
def test_build_orm(self, mock_boto_client):
33+
hcclient = MagicMock()
34+
hcclient.list_tables.return_value = mock_list_tables_response
35+
hcclient.list_table_columns.return_value = mock_list_columns_response
36+
create_client = MagicMock()
37+
create_client.create_client.return_value = hcclient
38+
mock_boto_client.ClientCreator.return_value = create_client
39+
40+
hcb = HoneycodeORMBuilder("dummy-workbook-id")
41+
hcb.buildORM()
42+
numberOfFilesCreated = len(os.listdir(os.getcwd() + '/orm'))
43+
print(str(numberOfFilesCreated))
44+
self.assertEqual(2,numberOfFilesCreated)
45+
46+
47+
# def test_build_insert_for_table(self):
48+
# self.fail()
49+
#
50+
# def test_build_print_statement(self):
51+
# self.fail()
52+
#
53+
# def test_build_var_alloc_for_table(self):
54+
# self.fail()
55+
#
56+
# def test_build_convert(self):
57+
# self.fail()
58+
#
59+
# def test_build_params_for_table(self):
60+
# self.fail()
61+
#
62+
# def test_get_table_id_by_name(self):
63+
# self.fail()

0 commit comments

Comments
 (0)