@@ -0,0 +1,215 @@
1+import websocket as ws
2+#this websocket-client module supports both python 2.7 and 3.x- the "websockets" module supports python 3.4+ but relies on asyncio. It might be possible to mix the modules in this driver or it make more sense to create a separate python 3.4+ database driver.
3+import exceptions
4+import json
5+
6+apilevel = '2.0'
7+threadsafety = 2
8+paramstyle = None #not applicable
9+
10+class Error(exceptions.StandardError):
11+ pass
12+
13+class Warning(exceptions.StandardError):
14+ pass
15+
16+class InterfaceError(Error):
17+ pass
18+
19+class DatabaseError(Error):
20+ pass
21+
22+class InternalError(DatabaseError):
23+ pass
24+
25+class OperationalError(DatabaseError):
26+ pass
27+
28+class ProgrammingError(DatabaseError):
29+ pass
30+
31+class IntegrityError(DatabaseError):
32+ pass
33+
34+class DataError(DatabaseError):
35+ pass
36+
37+class NotSupportedError(DatabaseError):
38+ pass
39+
40+class ProjectM36Connection(object):
41+ def __init__(self, proto, host, port, path, dbname):
42+ assert proto in ('ws', 'wss'), "proto must be one of 'ws' or 'wss'"
43+ self.proto = proto
44+ self.host = host
45+ self.port = port
46+ self.path = path
47+ self.dbname = dbname
48+ self.conn = None
49+
50+ def connect(self):
51+ port = ''
52+ if self.port:
53+ port = ':{}'.format(self.port)
54+
55+ path = ''
56+ if self.path:
57+ path = '/{}'.format(self.path)
58+
59+
60+ self.conn = ws.create_connection('{}://{}{}{}'.format(self.proto,
61+ self.host,
62+ port,
63+ path))
64+ self.conn.send('connectdb:{}'.format(self.dbname))
65+ result = self.conn.recv()
66+ print result
67+
68+ result = self.conn.recv()
69+ print result
70+
71+ return True
72+
73+ def close(self):
74+ if self.conn is None: #already closed
75+ raise ProgrammingError('attempt to close connection which was not open')
76+ self.conn.close()
77+ self.conn = None
78+
79+ def commit(self):
80+ self.executeTutorialD(':commit')
81+
82+ def rollback(self):
83+ self.executeTutorialD(':rollback')
84+
85+ def cursor(self):
86+ return Cursor(self)
87+
88+ def _send(self, t):
89+ print 'SEND:', t
90+ return self.conn.send(t)
91+
92+ def _recv(self):
93+ return self.conn.recv()
94+
95+class ProjectM36JSONEncoder(json.JSONEncoder):
96+ def default(self, obj):
97+ if isinstance(obj, RelationalExpr):
98+ return obj.as_json()
99+ else:
100+ super(ProjectM36JSONEncoder, self).default(obj)
101+
102+class ProjectM36JSONDecoder(json.JSONDecoder):
103+ def decode(self, s):
104+ if
105+ super(ProjectM36JSONDecoder, self).decode(s)
106+
107+class Cursor(object):
108+ def __init__(self, conn):
109+ self._arraysize = 1
110+ self._conn = conn
111+
112+ @property
113+ def description(self):
114+ return []
115+
116+ @property
117+ def rowcount(self):
118+ return 0
119+
120+ #def callproc(self): #not applicable
121+
122+ def close(self):
123+ return
124+
125+ def executeTutorialD(self, tutoriald):
126+ self.conn.send()
127+
128+ def execute(self, relationalExpression):
129+ relExprJson = json.dumps(relationalExpression, cls=ProjectM36JSONEncoder)
130+ self._conn._send('evalrelexpr:{}'.format(relExprJson))
131+ result = self._conn._recv()
132+ rel = json.loads(result, cls=ProjectM36JSONDecoder)
133+ return rel
134+
135+ def executemany(self, op, params):
136+ raise NotImplementedError()
137+
138+ def fetchone(self):
139+ return 0
140+
141+ def fetchmany(self):
142+ return 0
143+
144+ def fetchall(self):
145+ return 0
146+
147+ #def nextset(self): #not applicable
148+
149+ @property
150+ def arraysize(self):
151+ return self._arraysize
152+
153+ @arraysize.setter
154+ def set_arraysize(self, size):
155+ self._arraysize = size
156+
157+ def setinputsizes(self, sizes):
158+ return
159+
160+ def setoutputsize(self, size, column):
161+ return
162+
163+def connect(proto, host, port, path, dbname):
164+ conn = ProjectM36Connection(proto, host, port, path, dbname)
165+ conn.connect()
166+ return conn
167+
168+class RelationalExpr(object):
169+ def as_json(self):
170+ return {'tag':self.__class__.__name__,
171+ 'contents':self.json_contents()}
172+
173+class RelationVariable(RelationalExpr):
174+ def __init__(self, rvname):
175+ self.name = rvname
176+
177+ def json_contents(self):
178+ return [self.name, []]
179+
180+class Equals(RelationalExpr):
181+ def __init__(self, exprA, exprB):
182+ self.a = exprA
183+ self.b = exprB
184+'''
185+(Maybe [AttributeExprBase a]) [TupleExprBase a] |
186+ --- | Create and reference a relation from attributes and a tuple set.
187+ MakeStaticRelation Attributes RelationTupleSet |
188+ --- | Reference an existing relation in Haskell-space.
189+ ExistingRelation Relation |
190+ --MakeFunctionalRelation (creates a relation from a tuple-generating function, potentially infinite)
191+ --in Tutorial D, relational variables pick up the type of the first relation assigned to them
192+ --relational variables should also be able to be explicitly-typed like in Haskell
193+ --- | Reference a relation variable by its name.
194+ RelationVariable RelVarName a |
195+ --- | Create a projection over attribute names. (Note that the 'AttributeNames' structure allows for the names to be inverted.)
196+ Project AttributeNames (RelationalExprBase a) |
197+ --- | Create a union of two relational expressions. The expressions should have identical attributes.
198+ Union (RelationalExprBase a) (RelationalExprBase a) |
199+ --- | Create a join of two relational expressions. The join occurs on attributes which are identical. If the expressions have no overlapping attributes, the join becomes a cross-product of both tuple sets.
200+ Join (RelationalExprBase a) (RelationalExprBase a) |
201+ --- | Rename an attribute (first argument) to another (second argument).
202+ Rename AttributeName AttributeName (RelationalExprBase a) |
203+ --- | Return a relation containing all tuples of the first argument which do not appear in the second argument (minus).
204+ Difference (RelationalExprBase a) (RelationalExprBase a) |
205+ --- | Create a sub-relation composed of the first argument's attributes which will become an attribute of the result expression. The unreferenced attributes are not altered in the result but duplicate tuples in the projection of the expression minus the attribute names are compressed into one. For more information, <https://github.com/agentm/project-m36/blob/master/docs/introduction_to_the_relational_algebra.markdown#group read the relational algebra tutorial.>
206+ Group AttributeNames AttributeName (RelationalExprBase a) |
207+ --- | Create an expression to unwrap a sub-relation contained within at an attribute's name. Note that this is not always an inverse of a group operation.
208+ Ungroup AttributeName (RelationalExprBase a) |
209+ --- | Filter the tuples of the relational expression to only retain the tuples which evaluate against the restriction predicate to true.
210+ Restrict (RestrictionPredicateExprBase a) (RelationalExprBase a) |
211+ --- | Returns the true relation iff
212+ Equals (RelationalExprBase a) (RelationalExprBase a) |
213+ NotEquals (RelationalExprBase a) (RelationalExprBase a) |
214+ Extend (ExtendTupleExprBase a) (RelationalExprBase a)
215+'''