Merge pull request #31 from ltworf/column_types
Types per column, not per cell. Cast when loading.
This commit is contained in:
commit
8755236f94
@ -6,6 +6,7 @@ python:
|
||||
install:
|
||||
- pip install mypy
|
||||
- pip install xtermcolor
|
||||
- pip install typedload
|
||||
|
||||
script:
|
||||
- make mypy
|
||||
|
@ -1,4 +1,7 @@
|
||||
3.0
|
||||
- By default relations are saved as json. This allows to keep the type
|
||||
- Dates can no longer be added or subtracted
|
||||
- Types are now inferred by column, no longer by cell
|
||||
- Relations now use frozenset internally and are immutable
|
||||
- Refactored parser to use better typing
|
||||
- Refactored and fixed some optimizations
|
||||
|
4
debian/control
vendored
4
debian/control
vendored
@ -3,7 +3,7 @@ Section: math
|
||||
Priority: optional
|
||||
Maintainer: Salvo 'LtWorf' Tomaselli <tiposchi@tiscali.it>
|
||||
Build-Depends: debhelper-compat (= 13), debhelper (>= 13), python3, dh-python, python3-xtermcolor, pyqt5-dev-tools,
|
||||
python3-distutils
|
||||
python3-distutils, python3-typedload
|
||||
Standards-Version: 4.5.0
|
||||
X-Python3-Version: >= 3.8
|
||||
Homepage: https://ltworf.github.io/relational/
|
||||
@ -12,7 +12,7 @@ Rules-Requires-Root: no
|
||||
Package: python3-relational
|
||||
Architecture: all
|
||||
Section: python
|
||||
Depends: ${misc:Depends}, ${python3:Depends}
|
||||
Depends: ${misc:Depends}, ${python3:Depends}, python3-typedload
|
||||
Description: Educational tool for relational algebra (standalone module)
|
||||
Relational is primarily a tool to provide a workspace for experimenting with
|
||||
relational algebra, an offshoot of first-order logic.
|
||||
|
@ -57,7 +57,7 @@ def load_relations():
|
||||
|
||||
print ("Loading relation %s with name %s..." % (i, relname))
|
||||
|
||||
rels[relname] = relation.Relation.load('%s%s' % (examples_path, i))
|
||||
rels[relname] = relation.Relation.load_csv('%s%s' % (examples_path, i))
|
||||
print('done')
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Relational
|
||||
# Copyright (C) 2008-2017 Salvo "LtWorf" Tomaselli
|
||||
# Copyright (C) 2008-2020 Salvo "LtWorf" Tomaselli
|
||||
#
|
||||
# Relation is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@ -90,8 +90,15 @@ class UserInterface:
|
||||
|
||||
def load(self, filename: str, name: str) -> None:
|
||||
'''Loads a relation from file, and gives it a name to
|
||||
be used in subsequent queries.'''
|
||||
rel = Relation.load(filename)
|
||||
be used in subsequent queries.
|
||||
|
||||
Files ending with .csv are loaded as csv, the others are
|
||||
loaded as json.
|
||||
'''
|
||||
if filename.endswith('.csv'):
|
||||
rel = Relation.load_csv(filename)
|
||||
else:
|
||||
rel = Relation.load(filename)
|
||||
self.set_relation(name, rel)
|
||||
|
||||
def unload(self, name: str) -> None:
|
||||
@ -100,7 +107,10 @@ class UserInterface:
|
||||
|
||||
def store(self, filename: str, name: str) -> None:
|
||||
'''Stores a relation to file.'''
|
||||
raise Exception('Not implemented')
|
||||
if filename.endswith('.csv'):
|
||||
self.relations[name].save_csv(filename)
|
||||
else:
|
||||
self.relations[name].save(filename)
|
||||
|
||||
def session_dump(self, filename: Optional[str] = None) -> Optional[str]:
|
||||
'''
|
||||
@ -161,8 +171,12 @@ class UserInterface:
|
||||
if len(name) == 0:
|
||||
return None
|
||||
|
||||
if (name.endswith(".csv")): # removes the extension
|
||||
name = name[:-4]
|
||||
# Removing the extension
|
||||
try:
|
||||
pos = name.rindex('.')
|
||||
except ValueError:
|
||||
return None
|
||||
name = name[:pos]
|
||||
|
||||
if not is_valid_relation_name(name):
|
||||
return None
|
||||
|
@ -19,10 +19,10 @@
|
||||
# This module provides a classes to represent relations and to perform
|
||||
# relational operations on them.
|
||||
|
||||
import csv
|
||||
from itertools import chain, repeat, product as iproduct
|
||||
from collections import deque
|
||||
from typing import *
|
||||
from typing import FrozenSet, Iterable, List, Dict, Tuple, Optional
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
from relational.rtypes import *
|
||||
@ -33,8 +33,8 @@ __all__ = [
|
||||
'Header',
|
||||
]
|
||||
|
||||
|
||||
class Relation(NamedTuple):
|
||||
@dataclass(repr=True, unsafe_hash=False, frozen=True)
|
||||
class Relation:
|
||||
'''
|
||||
This object defines a relation (as a group of consistent tuples) and operations.
|
||||
|
||||
@ -58,47 +58,57 @@ class Relation(NamedTuple):
|
||||
method.
|
||||
'''
|
||||
header: 'Header'
|
||||
content: FrozenSet[Tuple[Rstring, ...]]
|
||||
content: FrozenSet[Tuple[CastValue, ...]]
|
||||
|
||||
@staticmethod
|
||||
def load(filename: Union[str, Path]) -> 'Relation':
|
||||
def load_csv(filename: Union[str, Path]) -> 'Relation':
|
||||
'''
|
||||
Load a relation object from a csv file.
|
||||
|
||||
The 1st row is the header and the other rows are the content.
|
||||
|
||||
Types will be inferred automatically
|
||||
'''
|
||||
import csv
|
||||
with open(filename) as fp:
|
||||
reader = csv.reader(fp) # Creating a csv reader
|
||||
header = Header(next(reader)) # read 1st line
|
||||
return Relation.create_from(header, reader)
|
||||
|
||||
@staticmethod
|
||||
def create_from(header: Iterable[str], content: Iterable[Iterable[str]]) -> 'Relation':
|
||||
def load(filename: Union[str, Path]) -> 'Relation':
|
||||
'''
|
||||
Iterator for the header, and iterator for the content.
|
||||
Load a relation object from a json file.
|
||||
'''
|
||||
header = Header(header)
|
||||
r_content: List[Tuple[Rstring, ...]] = []
|
||||
for row in content:
|
||||
content_row: Tuple[Rstring, ...] = tuple(Rstring(i) for i in row)
|
||||
if len(content_row) != len(header):
|
||||
raise ValueError(f'Line {row} contains an incorrect amount of values')
|
||||
r_content.append(content_row)
|
||||
return Relation(header, frozenset(r_content))
|
||||
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.content)
|
||||
|
||||
def __contains__(self, key):
|
||||
return key in self.content
|
||||
with open(filename) as fp:
|
||||
from json import load as jload
|
||||
from typedload import load
|
||||
loaded = jload(fp)
|
||||
header = Header(loaded['header'])
|
||||
content = []
|
||||
for row in loaded['content']:
|
||||
if len(row) != len(header):
|
||||
raise ValueError(f'Line {row} contains an incorrect amount of values')
|
||||
t_row: Tuple[Optional[Union[int, float, str, Rdate]], ...] = load(row, Tuple[Optional[Union[int, float, str, Rdate]], ...]) # type: ignore
|
||||
content.append(t_row)
|
||||
return Relation(header, frozenset(content))
|
||||
|
||||
def save(self, filename: Union[Path, str]) -> None:
|
||||
'''
|
||||
Saves the relation in a file.
|
||||
Will save using the json format
|
||||
'''
|
||||
with open(filename, 'w') as fp:
|
||||
from json import dump as jdump
|
||||
from typedload import dump
|
||||
jdump(dump(self), fp)
|
||||
|
||||
def save_csv(self, filename: Union[Path, str]) -> None:
|
||||
'''
|
||||
Saves the relation in a file. Will save using the csv
|
||||
format as defined in RFC4180.
|
||||
'''
|
||||
|
||||
import csv
|
||||
with open(filename, 'w') as fp:
|
||||
writer = csv.writer(fp) # Creating csv writer
|
||||
|
||||
@ -109,6 +119,40 @@ class Relation(NamedTuple):
|
||||
# Writing content, already in the correct format
|
||||
writer.writerows(self.content)
|
||||
|
||||
@staticmethod
|
||||
def create_from(header: Iterable[str], content: Iterable[List[str]]) -> 'Relation':
|
||||
'''
|
||||
Iterator for the header, and iterator for the content.
|
||||
|
||||
This will infer types.
|
||||
'''
|
||||
header = Header(header)
|
||||
r_content = []
|
||||
guessed_types = list(repeat({Rdate, float, int, str}, len(header)))
|
||||
|
||||
for row in content:
|
||||
if len(row) != len(header):
|
||||
raise ValueError(f'Line {row} contains an incorrect amount of values')
|
||||
r_content.append(row)
|
||||
|
||||
# Guess types
|
||||
for i, value in enumerate(row):
|
||||
guessed_types[i] = guessed_types[i].intersection(guess_type(value))
|
||||
|
||||
typed_content = []
|
||||
for r in r_content:
|
||||
t = tuple(cast(v, guessed_types[i]) for i, v in enumerate(r))
|
||||
typed_content.append(t)
|
||||
|
||||
return Relation(header, frozenset(typed_content))
|
||||
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.content)
|
||||
|
||||
def __contains__(self, key):
|
||||
return key in self.content
|
||||
|
||||
def _rearrange(self, other: 'Relation') -> 'Relation':
|
||||
'''If two relations share the same attributes in a different order, this method
|
||||
will use projection to make them have the same attributes' order.
|
||||
@ -129,8 +173,6 @@ class Relation(NamedTuple):
|
||||
'''
|
||||
Selection, expr must be a valid Python expression; can contain field names.
|
||||
'''
|
||||
header = Header(self.header)
|
||||
|
||||
try:
|
||||
c_expr = compile(expr, 'selection', 'eval')
|
||||
except:
|
||||
@ -139,7 +181,7 @@ class Relation(NamedTuple):
|
||||
content = []
|
||||
for i in self.content:
|
||||
# Fills the attributes dictionary with the values of the tuple
|
||||
attributes = {attr: i[j].autocast()
|
||||
attributes = {attr: i[j]
|
||||
for j, attr in enumerate(self.header)
|
||||
}
|
||||
|
||||
@ -147,8 +189,8 @@ class Relation(NamedTuple):
|
||||
if eval(c_expr, attributes):
|
||||
content.append(i)
|
||||
except Exception as e:
|
||||
raise Exception(f'Failed to evaluate {expr}\n{e}')
|
||||
return Relation(header, frozenset(content))
|
||||
raise Exception(f'Failed to evaluate {expr} with {attributes}\n{e}')
|
||||
return Relation(self.header, frozenset(content))
|
||||
|
||||
def product(self, other: 'Relation') -> 'Relation':
|
||||
'''
|
||||
@ -267,9 +309,7 @@ class Relation(NamedTuple):
|
||||
def outer_right(self, other: 'Relation') -> 'Relation':
|
||||
'''
|
||||
Outer right join. Considers self as left and param as right. If the
|
||||
tuple has no corrispondence, empy attributes are filled with a "---"
|
||||
string. This is due to the fact that the None token would cause
|
||||
problems when saving and reloading the relation.
|
||||
tuple has no corrispondence, empy attributes are filled with a None.
|
||||
Just like natural join, it works considering shared attributes.
|
||||
'''
|
||||
return other.outer_left(self)
|
||||
@ -278,7 +318,6 @@ class Relation(NamedTuple):
|
||||
'''
|
||||
See documentation for outer_right
|
||||
'''
|
||||
|
||||
shared = self.header.intersection(other.header)
|
||||
|
||||
# Creating the header with all the fields, done like that because order is
|
||||
@ -310,7 +349,7 @@ class Relation(NamedTuple):
|
||||
added = True
|
||||
# If it didn't partecipate, adds it
|
||||
if not added:
|
||||
item = chain(i, repeat(Rstring('---'), len(noid)))
|
||||
item = chain(i, repeat(None, len(noid)))
|
||||
content.append(tuple(item))
|
||||
|
||||
return Relation(header, frozenset(content))
|
||||
@ -373,18 +412,18 @@ class Relation(NamedTuple):
|
||||
m_len = [len(i) for i in self.header] # Maximum lenght string
|
||||
|
||||
for f in self.content:
|
||||
for col, i in enumerate(f):
|
||||
for col, i in enumerate(str(val) for val in f):
|
||||
if len(i) > m_len[col]:
|
||||
m_len[col] = len(i)
|
||||
|
||||
res = ""
|
||||
for f, attr in enumerate(self.header):
|
||||
res += "%s" % (attr.ljust(2 + m_len[f]))
|
||||
res += attr.ljust(2 + m_len[f])
|
||||
|
||||
for r in self.content:
|
||||
res += "\n"
|
||||
for col, i in enumerate(r):
|
||||
res += "%s" % (i.ljust(2 + m_len[col]))
|
||||
for col, i in enumerate(str(val) for val in r):
|
||||
res += i.ljust(2 + m_len[col])
|
||||
|
||||
return res
|
||||
|
||||
|
@ -23,124 +23,76 @@
|
||||
import datetime
|
||||
import keyword
|
||||
import re
|
||||
from typing import Union
|
||||
from typing import Union, Set, Any, Callable, Type, Optional
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
RELATION_NAME_REGEXP = re.compile(r'^[_a-z][_a-z0-9]*$', re.IGNORECASE)
|
||||
|
||||
|
||||
class Rstring(str):
|
||||
|
||||
'''String subclass with some custom methods'''
|
||||
|
||||
int_regexp = re.compile(r'^[\+\-]{0,1}[0-9]+$')
|
||||
float_regexp = re.compile(r'^[\+\-]{0,1}[0-9]+(\.([0-9])+)?$')
|
||||
date_regexp = re.compile(
|
||||
_date_regexp = re.compile(
|
||||
r'^([0-9]{1,4})(\\|-|/)([0-9]{1,2})(\\|-|/)([0-9]{1,2})$'
|
||||
)
|
||||
|
||||
def autocast(self) -> Union[int, float, 'Rdate', 'Rstring']:
|
||||
'''
|
||||
Returns the automatic cast for this
|
||||
value.
|
||||
'''
|
||||
try:
|
||||
return self._autocast
|
||||
except:
|
||||
pass
|
||||
|
||||
self._autocast = self # type: Union[int, float, 'Rdate', 'Rstring']
|
||||
if len(self) > 0:
|
||||
if self.isInt():
|
||||
self._autocast = int(self)
|
||||
elif self.isFloat():
|
||||
self._autocast = float(self)
|
||||
elif self.isDate():
|
||||
self._autocast = Rdate(self)
|
||||
return self._autocast
|
||||
|
||||
def isInt(self) -> bool:
|
||||
'''Returns true if the string represents an int number
|
||||
it only considers as int numbers the strings matching
|
||||
the following regexp:
|
||||
r'^[\+\-]{0,1}[0-9]+$'
|
||||
'''
|
||||
return Rstring.int_regexp.match(self) is not None
|
||||
|
||||
def isFloat(self) -> bool:
|
||||
'''Returns true if the string represents a float number
|
||||
it only considers as float numbers, the strings matching
|
||||
the following regexp:
|
||||
r'^[\+\-]{0,1}[0-9]+(\.([0-9])+)?$'
|
||||
'''
|
||||
return Rstring.float_regexp.match(self) is not None
|
||||
|
||||
def isDate(self) -> bool:
|
||||
'''Returns true if the string represents a date,
|
||||
in the format YYYY-MM-DD. as separators '-' , '\', '/' are allowed.
|
||||
As side-effect, the date object will be stored for future usage, so
|
||||
no more parsings are needed
|
||||
'''
|
||||
try:
|
||||
return self._isdate # type: ignore
|
||||
except:
|
||||
pass
|
||||
|
||||
r = Rstring.date_regexp.match(self)
|
||||
if r is None:
|
||||
self._isdate = False
|
||||
self._date = None
|
||||
return False
|
||||
|
||||
try: # Any of the following operations can generate an exception, if it happens, we aren't dealing with a date
|
||||
year = int(r.group(1))
|
||||
month = int(r.group(3))
|
||||
day = int(r.group(5))
|
||||
d = datetime.date(year, month, day)
|
||||
self._isdate = True
|
||||
self._date = d
|
||||
return True
|
||||
except:
|
||||
self._isdate = False
|
||||
self._date = None
|
||||
return False
|
||||
|
||||
def getDate(self):
|
||||
'''Returns the datetime.date object or None'''
|
||||
try:
|
||||
return self._date
|
||||
except:
|
||||
self.isDate()
|
||||
return self._date
|
||||
CastValue = Optional[Union[str, int, float, 'Rdate']]
|
||||
|
||||
|
||||
class Rdate (object):
|
||||
def guess_type(value: str) -> Set[Union[Callable[[Any], Any], Type['Rdate']]]:
|
||||
r: Set[Union[Callable[[Any], Any], Type['Rdate']]] = {str}
|
||||
if _date_regexp.match(value) is not None:
|
||||
r.add(Rdate)
|
||||
|
||||
try:
|
||||
int(value)
|
||||
r.add(int)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
try:
|
||||
float(value)
|
||||
r.add(float)
|
||||
except ValueError:
|
||||
pass
|
||||
return r
|
||||
|
||||
|
||||
def cast(value: str, guesses: Set) -> CastValue:
|
||||
if int in guesses:
|
||||
return int(value)
|
||||
if Rdate in guesses:
|
||||
return Rdate.create(value)
|
||||
if float in guesses:
|
||||
return float(value)
|
||||
return value
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Rdate:
|
||||
'''Represents a date'''
|
||||
year: int
|
||||
month: int
|
||||
day: int
|
||||
|
||||
def __init__(self, date):
|
||||
'''date: A string representing a date'''
|
||||
if not isinstance(date, Rstring):
|
||||
date = Rstring(date)
|
||||
@property
|
||||
def intdate(self) -> datetime.date:
|
||||
return datetime.date(self.year, self.month, self.day)
|
||||
|
||||
self.intdate = date.getDate()
|
||||
self.day = self.intdate.day
|
||||
self.month = self.intdate.month
|
||||
self.weekday = self.intdate.weekday()
|
||||
self.year = self.intdate.year
|
||||
@property
|
||||
def weekday(self) -> int:
|
||||
return self.intdate.weekday()
|
||||
|
||||
def __hash__(self):
|
||||
return self.intdate.__hash__()
|
||||
@staticmethod
|
||||
def create(date: str) -> 'Rdate':
|
||||
'''date: A string representing a date YYYY-MM-DD'''
|
||||
r = _date_regexp.match(date)
|
||||
if not r:
|
||||
raise ValueError(f'{date} is not a valid date')
|
||||
|
||||
year = int(r.group(1))
|
||||
month = int(r.group(3))
|
||||
day = int(r.group(5))
|
||||
return Rdate(year, month, day)
|
||||
|
||||
def __str__(self):
|
||||
return self.intdate.__str__()
|
||||
|
||||
def __add__(self, days):
|
||||
res = self.intdate + datetime.timedelta(days)
|
||||
return Rdate(res.__str__())
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.intdate == other.intdate
|
||||
|
||||
def __ge__(self, other):
|
||||
return self.intdate >= other.intdate
|
||||
|
||||
@ -153,12 +105,6 @@ class Rdate (object):
|
||||
def __lt__(self, other):
|
||||
return self.intdate < other.intdate
|
||||
|
||||
def __ne__(self, other):
|
||||
return self.intdate != other.intdate
|
||||
|
||||
def __sub__(self, other):
|
||||
return (self.intdate - other.intdate).days
|
||||
|
||||
|
||||
def is_valid_relation_name(name: str) -> bool:
|
||||
'''Checks if a name is valid for a relation.
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Relational
|
||||
# Copyright (C) 2008-2015 Salvo "LtWorf" Tomaselli
|
||||
# Copyright (C) 2008-2020 Salvo "LtWorf" Tomaselli
|
||||
#
|
||||
# Relational is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@ -52,13 +52,13 @@ class creatorForm(QtWidgets.QDialog):
|
||||
|
||||
for i in rel.content:
|
||||
self.table.insertRow(self.table.rowCount())
|
||||
for j in range(len(i)):
|
||||
for j, value in enumerate(i):
|
||||
if value is None:
|
||||
raise Exception('Relation contains a None value and cannot be edited from the GUI')
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
item.setText(i[j])
|
||||
item.setText(str(value))
|
||||
self.table.setItem(self.table.rowCount() - 1, j, item)
|
||||
|
||||
pass
|
||||
|
||||
def setup_empty(self):
|
||||
self.table.insertColumn(0)
|
||||
self.table.insertColumn(0)
|
||||
@ -142,11 +142,3 @@ def edit_relation(rel=None):
|
||||
|
||||
Form.exec_()
|
||||
return Form.result_relation
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
app = QtGui.QApplication(sys.argv)
|
||||
r = relation.relation(
|
||||
"/home/salvo/dev/relational/trunk/samples/people.csv")
|
||||
print (edit_relation(r))
|
||||
|
@ -249,7 +249,13 @@ class relForm(QtWidgets.QMainWindow):
|
||||
for i in rel.content:
|
||||
item = QtWidgets.QTreeWidgetItem()
|
||||
for j,k in enumerate(i):
|
||||
item.setText(j, k)
|
||||
if k is None:
|
||||
item.setBackground(j, QtGui.QBrush(QtCore.Qt.darkRed, QtCore.Qt.Dense4Pattern))
|
||||
elif isinstance(k, (int, float)):
|
||||
item.setForeground(j, QtGui.QPalette().link())
|
||||
elif not isinstance(k, str):
|
||||
item.setForeground(j, QtGui.QPalette().brightText())
|
||||
item.setText(j, str(k))
|
||||
self.ui.table.addTopLevelItem(item)
|
||||
|
||||
# Sets columns
|
||||
@ -286,13 +292,13 @@ class relForm(QtWidgets.QMainWindow):
|
||||
filename = QtWidgets.QFileDialog.getSaveFileName(
|
||||
self, QtWidgets.QApplication.translate("Form", "Save Relation"),
|
||||
"",
|
||||
QtWidgets.QApplication.translate("Form", "Relations (*.csv)")
|
||||
QtWidgets.QApplication.translate("Form", "Json relations (*.json);;CSV relations (*.csv)")
|
||||
)[0]
|
||||
if (len(filename) == 0): # Returns if no file was selected
|
||||
return
|
||||
|
||||
relname = self.ui.lstRelations.selectedItems()[0].text()
|
||||
self.user_interface.relations[relname].save(filename)
|
||||
self.user_interface.store(filename, relname)
|
||||
|
||||
def unloadRelation(self):
|
||||
for i in self.ui.lstRelations.selectedItems():
|
||||
@ -306,9 +312,15 @@ class relForm(QtWidgets.QMainWindow):
|
||||
def editRelation(self):
|
||||
from relational_gui import creator
|
||||
for i in self.ui.lstRelations.selectedItems():
|
||||
result = creator.edit_relation(
|
||||
self.user_interface.get_relation(i.text())
|
||||
)
|
||||
try:
|
||||
result = creator.edit_relation(
|
||||
self.user_interface.get_relation(i.text())
|
||||
)
|
||||
except Exception as e:
|
||||
QtWidgets.QMessageBox.warning(
|
||||
self, QtWidgets.QApplication.translate("Form", "Error"), str(e)
|
||||
)
|
||||
return
|
||||
if result != None:
|
||||
self.user_interface.set_relation(i.text(), result)
|
||||
self.updateRelations()
|
||||
@ -410,7 +422,7 @@ class relForm(QtWidgets.QMainWindow):
|
||||
"",
|
||||
QtWidgets.QApplication.translate(
|
||||
"Form",
|
||||
"Relations (*.csv);;Text Files (*.txt);;All Files (*)"
|
||||
"Relations (*.json *.csv);;Text Files (*.txt);;All Files (*)"
|
||||
)
|
||||
)
|
||||
filenames = f[0]
|
||||
|
@ -106,8 +106,7 @@ class SimpleCompleter:
|
||||
repr(text), state, repr(response))
|
||||
return response
|
||||
|
||||
|
||||
relations = {}
|
||||
ui = maintenance.UserInterface()
|
||||
completer = SimpleCompleter(
|
||||
['SURVEY', 'LIST', 'LOAD ', 'UNLOAD ', 'HELP ', 'QUIT', 'SAVE ', '_PRODUCT ', '_UNION ', '_INTERSECTION ',
|
||||
'_DIFFERENCE ', '_JOIN ', '_LJOIN ', '_RJOIN ', '_FJOIN ', '_PROJECTION ', '_RENAME_TO ', '_SELECTION ', '_RENAME ', '_DIVISION '])
|
||||
@ -137,7 +136,7 @@ def load_relation(filename: str, defname: Optional[str]) -> Optional[str]:
|
||||
"%s is not a valid relation name" % defname, ERROR_COLOR), file=sys.stderr)
|
||||
return None
|
||||
try:
|
||||
relations[defname] = relation.Relation.load(filename)
|
||||
ui.load(filename, defname)
|
||||
|
||||
completer.add_completion(defname)
|
||||
printtty(colorize("Loaded relation %s" % defname, COLOR_GREEN))
|
||||
@ -204,7 +203,7 @@ def exec_line(command: str) -> None:
|
||||
elif command.startswith('HELP'):
|
||||
help(command)
|
||||
elif command == 'LIST': # Lists all the loaded relations
|
||||
for i in relations:
|
||||
for i in ui.relations:
|
||||
if not i.startswith('_'):
|
||||
print(i)
|
||||
elif command == 'SURVEY':
|
||||
@ -225,9 +224,10 @@ def exec_line(command: str) -> None:
|
||||
pars = command.split(' ')
|
||||
if len(pars) < 2:
|
||||
print(colorize("Missing parameter", ERROR_COLOR))
|
||||
return
|
||||
if pars[1] in relations:
|
||||
del relations[pars[1]]
|
||||
elif len(pars) > 2:
|
||||
print(colorize("Too many parameter", ERROR_COLOR))
|
||||
if pars[1] in ui.relations:
|
||||
ui.unload(pars[1])
|
||||
completer.remove_completion(pars[1])
|
||||
else:
|
||||
print(colorize("No such relation %s" % pars[1], ERROR_COLOR))
|
||||
@ -240,11 +240,8 @@ def exec_line(command: str) -> None:
|
||||
filename = pars[1]
|
||||
defname = pars[2]
|
||||
|
||||
if defname not in relations:
|
||||
print(colorize("No such relation %s" % defname, ERROR_COLOR))
|
||||
return
|
||||
try:
|
||||
relations[defname].save(filename)
|
||||
ui.store(filename, defname)
|
||||
except Exception as e:
|
||||
print(colorize(e, ERROR_COLOR))
|
||||
else:
|
||||
@ -298,7 +295,7 @@ def exec_query(command: str) -> None:
|
||||
# Execute query
|
||||
try:
|
||||
pyquery = parser.parse(query)
|
||||
result = pyquery(relations)
|
||||
result = pyquery(ui.relations)
|
||||
|
||||
printtty(colorize("-> query: %s" % pyquery, COLOR_GREEN))
|
||||
|
||||
@ -306,7 +303,7 @@ def exec_query(command: str) -> None:
|
||||
print()
|
||||
print(result)
|
||||
|
||||
relations[relname] = result
|
||||
ui.relations[relname] = result
|
||||
|
||||
completer.add_completion(relname)
|
||||
except Exception as e:
|
||||
|
@ -1,9 +1 @@
|
||||
id,name,chief,age
|
||||
0,jack,0,22
|
||||
1,carl,0,20
|
||||
2,john,1,30
|
||||
3,dean,1,33
|
||||
4,eve,0,25
|
||||
5,duncan,4,30
|
||||
6,paul,4,30
|
||||
7,alia,1,28
|
||||
{"content": [[1, "carl", 0, 20], [2, "john", 1, 30], [3, "dean", 1, 33], [5, "duncan", 4, 30], [0, "jack", 0, 22], [4, "eve", 0, 25], [6, "paul", 4, 30], [7, "alia", 1, 28]], "header": ["id", "name", "chief", "age"]}
|
@ -1,9 +1 @@
|
||||
id,name,chief,age
|
||||
0,jack,0,22
|
||||
1,carl,0,20
|
||||
2,john,1,30
|
||||
3,dean,1,33
|
||||
4,eve,0,25
|
||||
5,duncan,4,30
|
||||
6,paul,4,30
|
||||
7,alia,1,28
|
||||
{"content": [[1, "carl", 0, 20], [2, "john", 1, 30], [3, "dean", 1, 33], [5, "duncan", 4, 30], [0, "jack", 0, 22], [4, "eve", 0, 25], [6, "paul", 4, 30], [7, "alia", 1, 28]], "header": ["id", "name", "chief", "age"]}
|
@ -1,9 +1 @@
|
||||
id,name,chief,age
|
||||
0,jack,0,22
|
||||
1,carl,0,20
|
||||
2,john,1,30
|
||||
3,dean,1,33
|
||||
4,eve,0,25
|
||||
5,duncan,4,30
|
||||
6,paul,4,30
|
||||
7,alia,1,28
|
||||
{"content": [[1, "carl", 0, 20], [2, "john", 1, 30], [3, "dean", 1, 33], [5, "duncan", 4, 30], [0, "jack", 0, 22], [4, "eve", 0, 25], [6, "paul", 4, 30], [7, "alia", 1, 28]], "header": ["id", "name", "chief", "age"]}
|
@ -1,9 +1 @@
|
||||
id,name,chief,age
|
||||
0,jack,0,22
|
||||
1,carl,0,20
|
||||
2,john,1,30
|
||||
3,dean,1,33
|
||||
4,eve,0,25
|
||||
5,duncan,4,30
|
||||
6,paul,4,30
|
||||
7,alia,1,28
|
||||
{"content": [[1, "carl", 0, 20], [2, "john", 1, 30], [3, "dean", 1, 33], [5, "duncan", 4, 30], [0, "jack", 0, 22], [4, "eve", 0, 25], [6, "paul", 4, 30], [7, "alia", 1, 28]], "header": ["id", "name", "chief", "age"]}
|
@ -1,4 +1 @@
|
||||
name
|
||||
eve
|
||||
john
|
||||
duncan
|
||||
{"content": [["eve"], ["john"], ["duncan"]], "header": ["name"]}
|
@ -1,6 +1 @@
|
||||
id,name,chief,age,skill
|
||||
2,john,1,30,C
|
||||
7,alia,1,28,C
|
||||
5,duncan,4,30,C
|
||||
0,jack,0,22,C
|
||||
4,eve,0,25,C
|
||||
{"content": [[5, "duncan", 4, 30, "C"], [0, "jack", 0, 22, "C"], [4, "eve", 0, 25, "C"], [2, "john", 1, 30, "C"], [7, "alia", 1, 28, "C"]], "header": ["id", "name", "chief", "age", "skill"]}
|
@ -1,6 +1 @@
|
||||
"date"
|
||||
"2008-12-12"
|
||||
"2007-08-12"
|
||||
"1985-05-09"
|
||||
"1988-4-21"
|
||||
"1992-7-27"
|
||||
{"content": [[{"day": 12, "year": 2008, "month": 12}], [{"day": 9, "year": 1985, "month": 5}], [{"day": 21, "year": 1988, "month": 4}], [{"day": 27, "year": 1992, "month": 7}], [{"day": 12, "year": 2007, "month": 8}]], "header": ["date"]}
|
@ -1,3 +1 @@
|
||||
date
|
||||
2008-12-12
|
||||
2007-08-12
|
||||
{"content": [[{"day": 12, "year": 2008, "month": 12}], [{"day": 12, "year": 2007, "month": 8}]], "header": ["date"]}
|
@ -1,12 +1 @@
|
||||
id,name,chief,age,skill
|
||||
2,john,1,30,C
|
||||
7,alia,1,28,C
|
||||
1,carl,0,20,C++
|
||||
2,john,1,30,PHP
|
||||
7,alia,1,28,Python
|
||||
3,dean,1,33,C++
|
||||
7,alia,1,28,PHP
|
||||
0,jack,0,22,Python
|
||||
1,carl,0,20,Python
|
||||
0,jack,0,22,C
|
||||
1,carl,0,20,System Admin
|
||||
{"content": [[3, "dean", 1, 33, "C++"], [2, "john", 1, 30, "PHP"], [1, "carl", 0, 20, "C++"], [1, "carl", 0, 20, "Python"], [2, "john", 1, 30, "C"], [0, "jack", 0, 22, "Python"], [7, "alia", 1, 28, "Python"], [7, "alia", 1, 28, "PHP"], [1, "carl", 0, 20, "System Admin"], [0, "jack", 0, 22, "C"], [7, "alia", 1, 28, "C"]], "header": ["id", "name", "chief", "age", "skill"]}
|
@ -1,19 +1 @@
|
||||
id,skill,name,chief,age
|
||||
4,C++,eve,0,25
|
||||
4,C,eve,0,25
|
||||
7,C,alia,1,28
|
||||
9,Java,---,---,---
|
||||
0,Python,jack,0,22
|
||||
5,C,duncan,4,30
|
||||
4,Perl,eve,0,25
|
||||
2,C,john,1,30
|
||||
1,Python,carl,0,20
|
||||
5,Perl,duncan,4,30
|
||||
6,---,paul,4,30
|
||||
2,PHP,john,1,30
|
||||
0,C,jack,0,22
|
||||
7,Python,alia,1,28
|
||||
1,System Admin,carl,0,20
|
||||
7,PHP,alia,1,28
|
||||
1,C++,carl,0,20
|
||||
3,C++,dean,1,33
|
||||
{"content": [[7, "C", "alia", 1, 28], [2, "PHP", "john", 1, 30], [4, "C++", "eve", 0, 25], [7, "Python", "alia", 1, 28], [6, null, "paul", 4, 30], [0, "Python", "jack", 0, 22], [2, "C", "john", 1, 30], [1, "Python", "carl", 0, 20], [1, "System Admin", "carl", 0, 20], [3, "C++", "dean", 1, 33], [5, "Perl", "duncan", 4, 30], [5, "C", "duncan", 4, 30], [7, "PHP", "alia", 1, 28], [1, "C++", "carl", 0, 20], [0, "C", "jack", 0, 22], [9, "Java", null, null, null], [4, "C", "eve", 0, 25], [4, "Perl", "eve", 0, 25]], "header": ["id", "skill", "name", "chief", "age"]}
|
||||
|
@ -1,2 +1 @@
|
||||
id,name,chief,age
|
||||
4,eve,0,25
|
||||
{"content": [[4, "eve", 0, 25]], "header": ["id", "name", "chief", "age"]}
|
@ -1,2 +1 @@
|
||||
id,name,chief,age
|
||||
4,eve,0,25
|
||||
{"content": [[4, "eve", 0, 25]], "header": ["id", "name", "chief", "age"]}
|
@ -1,3 +1 @@
|
||||
name
|
||||
duncan
|
||||
eve
|
||||
{"content": [["eve"], ["duncan"]], "header": ["name"]}
|
@ -1,17 +1 @@
|
||||
id,name,chief,age,skill
|
||||
2,john,1,30,C
|
||||
7,alia,1,28,C
|
||||
4,eve,0,25,C++
|
||||
4,eve,0,25,C
|
||||
5,duncan,4,30,Perl
|
||||
1,carl,0,20,C++
|
||||
7,alia,1,28,PHP
|
||||
7,alia,1,28,Python
|
||||
3,dean,1,33,C++
|
||||
1,carl,0,20,Python
|
||||
2,john,1,30,PHP
|
||||
0,jack,0,22,Python
|
||||
0,jack,0,22,C
|
||||
1,carl,0,20,System Admin
|
||||
4,eve,0,25,Perl
|
||||
5,duncan,4,30,C
|
||||
{"content": [[2, "john", 1, 30, "PHP"], [5, "duncan", 4, 30, "Perl"], [2, "john", 1, 30, "C"], [4, "eve", 0, 25, "Perl"], [1, "carl", 0, 20, "System Admin"], [3, "dean", 1, 33, "C++"], [4, "eve", 0, 25, "C++"], [1, "carl", 0, 20, "C++"], [1, "carl", 0, 20, "Python"], [0, "jack", 0, 22, "Python"], [7, "alia", 1, 28, "Python"], [5, "duncan", 4, 30, "C"], [7, "alia", 1, 28, "PHP"], [4, "eve", 0, 25, "C"], [0, "jack", 0, 22, "C"], [7, "alia", 1, 28, "C"]], "header": ["id", "name", "chief", "age", "skill"]}
|
@ -1,18 +1 @@
|
||||
id,name,chief,age,skill
|
||||
2,john,1,30,C
|
||||
7,alia,1,28,C
|
||||
4,eve,0,25,C++
|
||||
6,paul,4,30,---
|
||||
5,duncan,4,30,Perl
|
||||
1,carl,0,20,C++
|
||||
7,alia,1,28,PHP
|
||||
4,eve,0,25,C
|
||||
7,alia,1,28,Python
|
||||
3,dean,1,33,C++
|
||||
1,carl,0,20,Python
|
||||
2,john,1,30,PHP
|
||||
0,jack,0,22,Python
|
||||
0,jack,0,22,C
|
||||
1,carl,0,20,System Admin
|
||||
4,eve,0,25,Perl
|
||||
5,duncan,4,30,C
|
||||
{"content": [[2, "john", 1, 30, "PHP"], [5, "duncan", 4, 30, "Perl"], [2, "john", 1, 30, "C"], [6, "paul", 4, 30, null], [4, "eve", 0, 25, "Perl"], [1, "carl", 0, 20, "System Admin"], [3, "dean", 1, 33, "C++"], [4, "eve", 0, 25, "C++"], [1, "carl", 0, 20, "C++"], [1, "carl", 0, 20, "Python"], [0, "jack", 0, 22, "Python"], [7, "alia", 1, 28, "Python"], [5, "duncan", 4, 30, "C"], [7, "alia", 1, 28, "PHP"], [4, "eve", 0, 25, "C"], [0, "jack", 0, 22, "C"], [7, "alia", 1, 28, "C"]], "header": ["id", "name", "chief", "age", "skill"]}
|
@ -1,2 +1 @@
|
||||
id,name,chief,age,rating
|
||||
1,carl,0,20,6
|
||||
{"content": [[1, "carl", 0, 20, 6]], "header": ["id", "name", "chief", "age", "rating"]}
|
@ -1,2 +1 @@
|
||||
date
|
||||
2008-12-12
|
||||
{"content": [[{"day": 12, "year": 2008, "month": 12}]], "header": ["date"]}
|
@ -1,9 +1 @@
|
||||
name,age
|
||||
eve,25
|
||||
dean,33
|
||||
carl,20
|
||||
paul,30
|
||||
john,30
|
||||
jack,22
|
||||
duncan,30
|
||||
alia,28
|
||||
{"content": [["eve", 25], ["duncan", 30], ["paul", 30], ["carl", 20], ["alia", 28], ["dean", 33], ["jack", 22], ["john", 30]], "header": ["name", "age"]}
|
@ -1,7 +1 @@
|
||||
name,age,chief_name,chief_age
|
||||
dean,33,carl,20
|
||||
alia,28,carl,20
|
||||
paul,30,eve,25
|
||||
eve,25,jack,22
|
||||
john,30,carl,20
|
||||
duncan,30,eve,25
|
||||
{"content": [["dean", 33, "carl", 20], ["duncan", 30, "eve", 25], ["john", 30, "carl", 20], ["alia", 28, "carl", 20], ["eve", 25, "jack", 22], ["paul", 30, "eve", 25]], "header": ["name", "age", "chief_name", "chief_age"]}
|
@ -1 +1 @@
|
||||
id,name,chief,age
|
||||
{"content": [], "header": ["id", "name", "chief", "age"]}
|
@ -1 +1 @@
|
||||
id,name,chief,age
|
||||
{"content": [], "header": ["id", "name", "chief", "age"]}
|
@ -1 +1 @@
|
||||
id,name,chief,age
|
||||
{"content": [], "header": ["id", "name", "chief", "age"]}
|
@ -1 +1 @@
|
||||
id,name,chief,age
|
||||
{"content": [], "header": ["id", "name", "chief", "age"]}
|
@ -1,9 +1 @@
|
||||
id,name,chief,age
|
||||
0,jack,0,22
|
||||
1,carl,0,20
|
||||
2,john,1,30
|
||||
3,dean,1,33
|
||||
4,eve,0,25
|
||||
5,duncan,4,30
|
||||
6,paul,4,30
|
||||
7,alia,1,28
|
||||
{"content": [[1, "carl", 0, 20], [2, "john", 1, 30], [3, "dean", 1, 33], [5, "duncan", 4, 30], [0, "jack", 0, 22], [4, "eve", 0, 25], [6, "paul", 4, 30], [7, "alia", 1, 28]], "header": ["id", "name", "chief", "age"]}
|
@ -1,9 +1 @@
|
||||
id,name,chief,age,room
|
||||
0,jack,0,22,1
|
||||
1,carl,0,20,4
|
||||
2,john,1,30,2
|
||||
3,dean,1,33,2
|
||||
4,eve,0,25,5
|
||||
5,duncan,4,30,1
|
||||
6,paul,4,30,5
|
||||
7,alia,1,28,1
|
||||
{"content": [[5, "duncan", 4, 30, 1], [4, "eve", 0, 25, 5], [0, "jack", 0, 22, 1], [2, "john", 1, 30, 2], [1, "carl", 0, 20, 4], [6, "paul", 4, 30, 5], [7, "alia", 1, 28, 1], [3, "dean", 1, 33, 2]], "header": ["id", "name", "chief", "age", "room"]}
|
@ -1,9 +1 @@
|
||||
id,name,chief,age,room
|
||||
0,jack,0,22,1
|
||||
1,carl,0,20,4
|
||||
2,john,1,30,2
|
||||
3,dean,1,33,2
|
||||
4,eve,0,25,5
|
||||
5,duncan,4,30,1
|
||||
6,paul,4,30,5
|
||||
7,alia,1,28,1
|
||||
{"content": [[5, "duncan", 4, 30, 1], [4, "eve", 0, 25, 5], [0, "jack", 0, 22, 1], [2, "john", 1, 30, 2], [1, "carl", 0, 20, 4], [6, "paul", 4, 30, 5], [7, "alia", 1, 28, 1], [3, "dean", 1, 33, 2]], "header": ["id", "name", "chief", "age", "room"]}
|
@ -1,13 +1 @@
|
||||
id,name,chief,age,room,phone
|
||||
0,jack,0,22,1,1516
|
||||
1,carl,0,20,4,1041
|
||||
2,john,1,30,2,1617
|
||||
3,dean,1,33,2,1617
|
||||
4,eve,0,25,5,9212
|
||||
5,duncan,4,30,1,1516
|
||||
6,paul,4,30,5,9212
|
||||
7,alia,1,28,1,1516
|
||||
---,---,---,---,"0","1515"
|
||||
---,---,---,---,"3","1601"
|
||||
---,---,---,---,"6","1424"
|
||||
---,---,---,---,"7","1294"
|
||||
{"content": [[0, "jack", 0, 22, 1, 1516], [null, null, null, null, 6, 1424], [null, null, null, null, 3, 1601], [7, "alia", 1, 28, 1, 1516], [2, "john", 1, 30, 2, 1617], [3, "dean", 1, 33, 2, 1617], [5, "duncan", 4, 30, 1, 1516], [4, "eve", 0, 25, 5, 9212], [1, "carl", 0, 20, 4, 1041], [null, null, null, null, 0, 1515], [null, null, null, null, 7, 1294], [6, "paul", 4, 30, 5, 9212]], "header": ["id", "name", "chief", "age", "room", "phone"]}
|
||||
|
@ -1,2 +1 @@
|
||||
id,name,chief,age,skill
|
||||
0,jack,0,22,C
|
||||
{"content": [[0, "jack", 0, 22, "C"]], "header": ["id", "name", "chief", "age", "skill"]}
|
@ -1,9 +1 @@
|
||||
id,n,chief,a
|
||||
0,jack,0,22
|
||||
1,carl,0,20
|
||||
2,john,1,30
|
||||
3,dean,1,33
|
||||
4,eve,0,25
|
||||
5,duncan,4,30
|
||||
6,paul,4,30
|
||||
7,alia,1,28
|
||||
{"content": [[1, "carl", 0, 20], [2, "john", 1, 30], [3, "dean", 1, 33], [5, "duncan", 4, 30], [0, "jack", 0, 22], [4, "eve", 0, 25], [6, "paul", 4, 30], [7, "alia", 1, 28]], "header": ["id", "n", "chief", "a"]}
|
@ -1,5 +1 @@
|
||||
i,name,chief,age
|
||||
0,jack,0,22
|
||||
2,john,1,30
|
||||
4,eve,0,25
|
||||
6,paul,4,30
|
||||
{"content": [[4, "eve", 0, 25], [6, "paul", 4, 30], [2, "john", 1, 30], [0, "jack", 0, 22]], "header": ["i", "name", "chief", "age"]}
|
@ -1,2 +1 @@
|
||||
phone,name
|
||||
1041,carl
|
||||
{"content": [[1041, "carl"]], "header": ["phone", "name"]}
|
@ -1,2 +1 @@
|
||||
id,name,chief,age,skill
|
||||
7,alia,1,28,PHP
|
||||
{"content": [[7, "alia", 1, 28, "PHP"]], "header": ["id", "name", "chief", "age", "skill"]}
|
@ -1,3 +1 @@
|
||||
name
|
||||
jack
|
||||
alia
|
||||
{"content": [["alia"], ["jack"]], "header": ["name"]}
|
@ -1 +1 @@
|
||||
id,name,chief,age
|
||||
{"content": [], "header": ["id", "name", "chief", "age"]}
|
@ -1,2 +1 @@
|
||||
id,name,chief,age
|
||||
2,john,1,30
|
||||
{"content": [[2, "john", 1, 30]], "header": ["id", "name", "chief", "age"]}
|
@ -1,18 +1 @@
|
||||
id,skill,name,chief,age
|
||||
4,C++,eve,0,25
|
||||
2,C,john,1,30
|
||||
1,Python,carl,0,20
|
||||
4,C,eve,0,25
|
||||
1,C++,carl,0,20
|
||||
7,C,alia,1,28
|
||||
9,Java,---,---,---
|
||||
2,PHP,john,1,30
|
||||
0,Python,jack,0,22
|
||||
4,Perl,eve,0,25
|
||||
5,C,duncan,4,30
|
||||
7,Python,alia,1,28
|
||||
1,System Admin,carl,0,20
|
||||
5,Perl,duncan,4,30
|
||||
7,PHP,alia,1,28
|
||||
0,C,jack,0,22
|
||||
3,C++,dean,1,33
|
||||
{"content": [[7, "C", "alia", 1, 28], [2, "PHP", "john", 1, 30], [4, "C++", "eve", 0, 25], [7, "Python", "alia", 1, 28], [0, "Python", "jack", 0, 22], [2, "C", "john", 1, 30], [1, "Python", "carl", 0, 20], [1, "System Admin", "carl", 0, 20], [3, "C++", "dean", 1, 33], [5, "Perl", "duncan", 4, 30], [5, "C", "duncan", 4, 30], [7, "PHP", "alia", 1, 28], [1, "C++", "carl", 0, 20], [0, "C", "jack", 0, 22], [9, "Java", null, null, null], [4, "C", "eve", 0, 25], [4, "Perl", "eve", 0, 25]], "header": ["id", "skill", "name", "chief", "age"]}
|
||||
|
@ -1,2 +1 @@
|
||||
id,skill,name,chief,age
|
||||
3,C++,dean,1,33
|
||||
{"content": [[3, "C++", "dean", 1, 33]], "header": ["id", "skill", "name", "chief", "age"]}
|
@ -1,3 +1 @@
|
||||
id,name,chief,age,skill
|
||||
0,jack,0,22,C
|
||||
4,eve,0,25,C
|
||||
{"content": [[4, "eve", 0, 25, "C"], [0, "jack", 0, 22, "C"]], "header": ["id", "name", "chief", "age", "skill"]}
|
@ -1 +1 @@
|
||||
σid=='---' (people⧓person_room ⧓ rooms)
|
||||
σ id is None (people⧓person_room ⧓ rooms)
|
||||
|
@ -1,5 +1 @@
|
||||
id,name,chief,age,room,phone
|
||||
---,---,---,---,"0","1515"
|
||||
---,---,---,---,"3","1601"
|
||||
---,---,---,---,"6","1424"
|
||||
---,---,---,---,"7","1294"
|
||||
{"content": [[null, null, null, null, 0, 1515], [null, null, null, null, 7, 1294], [null, null, null, null, 3, 1601], [null, null, null, null, 6, 1424]], "header": ["id", "name", "chief", "age", "room", "phone"]}
|
@ -1,4 +1 @@
|
||||
name,age,skill
|
||||
eve,25,Perl
|
||||
eve,25,C
|
||||
eve,25,C++
|
||||
{"content": [["eve", 25, "C++"], ["eve", 25, "C"], ["eve", 25, "Perl"]], "header": ["name", "age", "skill"]}
|
@ -1,8 +1 @@
|
||||
id,name,chief,age
|
||||
3,dean,1,33
|
||||
6,paul,4,30
|
||||
2,john,1,30
|
||||
0,jack,0,22
|
||||
7,alia,1,28
|
||||
1,carl,0,20
|
||||
5,duncan,4,30
|
||||
{"content": [[3, "dean", 1, 33], [5, "duncan", 4, 30], [1, "carl", 0, 20], [0, "jack", 0, 22], [2, "john", 1, 30], [6, "paul", 4, 30], [7, "alia", 1, 28]], "header": ["id", "name", "chief", "age"]}
|
@ -1 +1 @@
|
||||
id,name,chief,age
|
||||
{"content": [], "header": ["id", "name", "chief", "age"]}
|
@ -1,9 +1 @@
|
||||
id,name,chief,age
|
||||
0,jack,0,22
|
||||
1,carl,0,20
|
||||
2,john,1,30
|
||||
3,dean,1,33
|
||||
4,eve,0,25
|
||||
5,duncan,4,30
|
||||
6,paul,4,30
|
||||
7,alia,1,28
|
||||
{"content": [[1, "carl", 0, 20], [2, "john", 1, 30], [3, "dean", 1, 33], [5, "duncan", 4, 30], [0, "jack", 0, 22], [4, "eve", 0, 25], [6, "paul", 4, 30], [7, "alia", 1, 28]], "header": ["id", "name", "chief", "age"]}
|
@ -1,4 +1 @@
|
||||
id,name,chief,age
|
||||
7,alia,1,28
|
||||
4,eve,0,25
|
||||
0,jack,0,22
|
||||
{"content": [[4, "eve", 0, 25], [0, "jack", 0, 22], [7, "alia", 1, 28]], "header": ["id", "name", "chief", "age"]}
|
@ -1,9 +1 @@
|
||||
id,name,chief,age
|
||||
3,dean,1,33
|
||||
6,paul,4,30
|
||||
2,john,1,30
|
||||
0,jack,0,22
|
||||
7,alia,1,28
|
||||
1,carl,0,20
|
||||
4,eve,0,25
|
||||
5,duncan,4,30
|
||||
{"content": [[1, "carl", 0, 20], [2, "john", 1, 30], [3, "dean", 1, 33], [5, "duncan", 4, 30], [0, "jack", 0, 22], [4, "eve", 0, 25], [6, "paul", 4, 30], [7, "alia", 1, 28]], "header": ["id", "name", "chief", "age"]}
|
@ -1,9 +1 @@
|
||||
id,name,chief,age
|
||||
3,dean,1,33
|
||||
6,paul,4,30
|
||||
2,john,1,30
|
||||
0,jack,0,22
|
||||
7,alia,1,28
|
||||
1,carl,0,20
|
||||
4,eve,0,25
|
||||
5,duncan,4,30
|
||||
{"content": [[1, "carl", 0, 20], [2, "john", 1, 30], [3, "dean", 1, 33], [5, "duncan", 4, 30], [0, "jack", 0, 22], [4, "eve", 0, 25], [6, "paul", 4, 30], [7, "alia", 1, 28]], "header": ["id", "name", "chief", "age"]}
|
@ -1,9 +1 @@
|
||||
id,name,chief,age
|
||||
0,jack,0,22
|
||||
1,carl,0,20
|
||||
2,john,1,30
|
||||
3,dean,1,33
|
||||
4,eve,0,25
|
||||
5,duncan,4,30
|
||||
6,paul,4,30
|
||||
7,alia,1,28
|
||||
{"content": [[1, "carl", 0, 20], [2, "john", 1, 30], [3, "dean", 1, 33], [5, "duncan", 4, 30], [0, "jack", 0, 22], [4, "eve", 0, 25], [6, "paul", 4, 30], [7, "alia", 1, 28]], "header": ["id", "name", "chief", "age"]}
|
@ -1,4 +1 @@
|
||||
id,skill
|
||||
0,C
|
||||
2,C
|
||||
4,C
|
||||
{"content": [[2, "C"], [0, "C"], [4, "C"]], "header": ["id", "skill"]}
|
@ -1,8 +1 @@
|
||||
id,name,chief,age,skill
|
||||
4,eve,0,25,C
|
||||
5,duncan,4,30,C
|
||||
2,john,1,30,C
|
||||
7,alia,1,28,C
|
||||
4,eve,0,25,Perl
|
||||
5,duncan,4,30,Perl
|
||||
0,jack,0,22,C
|
||||
{"content": [[4, "eve", 0, 25, "C"], [5, "duncan", 4, 30, "C"], [0, "jack", 0, 22, "C"], [5, "duncan", 4, 30, "Perl"], [2, "john", 1, 30, "C"], [7, "alia", 1, 28, "C"], [4, "eve", 0, 25, "Perl"]], "header": ["id", "name", "chief", "age", "skill"]}
|
@ -1,3 +1 @@
|
||||
id,skill
|
||||
5,C
|
||||
7,C
|
||||
{"content": [[7, "C"], [5, "C"]], "header": ["id", "skill"]}
|
@ -1,3 +1 @@
|
||||
id,name,chief,age
|
||||
3,dean,1,33
|
||||
1,carl,0,20
|
||||
{"content": [[3, "dean", 1, 33], [1, "carl", 0, 20]], "header": ["id", "name", "chief", "age"]}
|
@ -1,8 +1 @@
|
||||
name,skill
|
||||
jack,C
|
||||
eve,Perl
|
||||
duncan,Perl
|
||||
duncan,C
|
||||
john,C
|
||||
alia,C
|
||||
eve,C
|
||||
{"content": [["jack", "C"], ["eve", "C"], ["duncan", "C"], ["alia", "C"], ["eve", "Perl"], ["duncan", "Perl"], ["john", "C"]], "header": ["name", "skill"]}
|
@ -1,2 +1 @@
|
||||
id,age,chief,name
|
||||
1,20,0,carl
|
||||
{"content": [[1, 20, 0, "carl"]], "header": ["id", "age", "chief", "name"]}
|
Loading…
x
Reference in New Issue
Block a user