source: lliurex-abies2pmb/trunk/fuentes/lliurex-abies2pmb-core.install/abies2pmb.py @ 4165

Last change on this file since 4165 was 4165, checked in by Juanma, 3 years ago

Added mdb-tools support

  • Property svn:executable set to *
File size: 15.6 KB
Line 
1#!/usr/bin/python3
2import os
3import datetime
4import subprocess
5import sys
6import tempfile
7# -*- coding: utf-8 -*-
8class abiesToPmb():
9        def __init__(self,mdbFile):
10                self.dbg=0
11               
12                #Dict with relations between pmb and abies
13                self.pmb_abies={}
14                self.pmb_abies["empr_categ"]=["TiposLector"]
15                self.pmb_abies["docs_location"]=["Ubicaciones"]
16                self.pmb_abies["authors"]=["Autores"]
17                self.pmb_abies["exemplaires"]=["Ejemplares"]
18                self.pmb_abies["notices"]=["Fondos","Fondos-CDUs"]
19                self.pmb_abies["collections"]=["Series"]
20                self.pmb_abies["notices_langues"]=["Fondos-Idiomas"]
21                self.pmb_abies["publishers"]=["Editoriales"]
22                self.pmb_abies["groupe"]=["Cursos"]
23                self.pmb_abies["indexint"]=["CDUs"]
24                self.pmb_abies["notices_tmp"]=["Fondos_all"]
25
26                #Blacklist pmb_abies tables.
27                self.blacklist=['notices_tmp']
28
29                #Dict with abies source fields for pmb
30                self.pmb_tables={}
31                self.pmb_tables["docs_location"]=[0,1,'','','','','','','','','','','','','','','','','','','','','','','']
32                self.pmb_tables["empr_categ"]=[0,1,'','','','']
33                self.pmb_tables["authors"]=[0,1,2,'','','','','','','','','','','','']
34                self.pmb_tables["publishers"]=[0,1,'','','','','','','','']
35                self.pmb_tables["groupe"]=[0,1,'','','','']
36                self.pmb_tables["exemplaires"]=[0,4,1,'','',13,'','',6,'','','','','','','','',9,'','','','','','','','','']
37                self.pmb_tables["collections"]=[0,1,'','','','','','']
38                self.pmb_tables["indexint"]=[0,1,'','','']
39                self.pmb_tables["notices_tmp"]=[0,1,2]
40                self.pmb_tables["notices"]=[0,1,14,15,16,13,'','',19,'',24,'',20,17,25,11,21,22,'',23,'','','','','',26,'','','','','','','','','','','','','','',6,'','','','','','','','','','','','','','']
41
42                #dict with needed virtual tables
43                self.virtual_tables={}
44                self.virtual_tables["CDUs"]={}
45                self.virtual_tables["CDUs"].update({'index 0':''})
46                self.virtual_tables["CDUs"].update({'index 1':'get Fondos_CDUs.1'})
47                self.virtual_tables['Series']={}
48                self.virtual_tables['Series'].update({'index 0':''})
49                self.virtual_tables['Series'].update({'index 1':'get Fondos.24'})
50                self.virtual_tables['Fondos_all']={'index 0':'get Fondos.0'}
51                self.virtual_tables['Fondos_all'].update({'index 1':''})
52                self.virtual_tables['Fondos_all'].update({'index 2':''})
53
54                #Dict whith field transformations
55                self.formatFields={}
56                self.formatFields['TiposLector']={'index 0':'add index 0 7'}
57                self.formatFields['Autores']={'index 1':'value 100=70,value 110=71,value 120=72,value 700=70'}
58                self.formatFields['Ejemplares']={'index 13':'concat 13,14,15'}
59                self.formatFields['Ejemplares'].update({'index 9':'date %m/%d/%y %H:%M:%S %Y-%m-%d %H:%M:%S'})
60                self.formatFields['CDUs']={'index 0':'inc 1 1000'}
61                self.formatFields['Series']={'index 0':'inc 1 1000'}
62                self.formatFields['Fondos']={'index 1':'value 1="a",value 2="g",value 3="m",value4="j",value 5="k",value 6="a",value 7="l"'}
63                self.formatFields['Fondos'].update({'index 13':'from Autores.2 on 13=0'})
64                self.formatFields['Fondos'].update({'index 24':'from Series.0 on 24=0'})
65                self.formatFields['Fondos'].update({'index 26':'from Fondos_all.2 on 0=1'})
66
67                #Dict whith special columns
68                self.formatTables={}
69                self.formatTables['CDUs']={'index 1':'uniq'}
70                self.formatTables['Series']={'index 1':'uniq'}
71                self.formatTables['Fondos_all']={'index 1':'from Fondos_CDUs.1 on 0=0'}
72                self.formatFields['Fondos_all']={'index 2':'from CDUs.0 on 0=1'}
73
74                #Dict with temp results
75                self.pmb_result={}
76
77                #Array with process order
78                self.executionOrder=['Ubicaciones','TiposLector','Autores','Editoriales','Cursos','Ejemplares','Series','CDUs','Fondos_all','Fondos']
79                #Tmp variables
80                self.workDir='/tmp/.abiesToPmb/'
81                self.tmpTableDict={}
82                self.tableValuesDict={}
83                self.tmpInc=0
84                #Mdb file
85                self.mdb=mdbFile
86        #def _init
87
88        def _debug(self,msg):
89                if self.dbg:
90                        print('Migrator: '+str(msg))
91        #def _debug
92
93        def _error(self,e):
94                print(str(e))
95        #def _error
96
97        ###
98        #Process array executionOrder
99        ###
100        def beginMigration(self):
101                returnValue=False
102                if self.exportMdb():
103                        for abiesTable in self.executionOrder:
104                                self.tmpInc=0
105                                self._debug("Processing "+abiesTable)
106                                self._loadTable(abiesTable)
107                                pmbTable=self._getTableEquivalence(abiesTable)
108                                self._generateSql(pmbTable,abiesTable)
109                        returnValue=True
110                        self._debug("Files generated for tables "+str(self.executionOrder))
111                return returnValue
112        #def beginMigration
113
114        def exportMdb(self):
115                returnValue=None
116                if os.path.exists(self.mdb):
117                        try:
118                                cmdOut=subprocess.check_output(['mdb-tables',self.mdb],universal_newlines=True)
119                                if cmdOut:
120                                        self.workDir=tempfile.mkdtemp()+"/"
121                                        tables=cmdOut.strip("\n")
122                                        listTables=tables.split(' ')
123                                        for table in listTables:
124                                                if table!='':
125                                                        cmdOut=subprocess.check_output(['mdb-export','-H','-d|||',self.mdb,table],universal_newlines=True)
126                                                        if cmdOut:
127                                                                f=open (self.workDir+table+".csv",'w')
128                                                                f.writelines(cmdOut)
129                                                                f.close()
130                                returnValue=True
131                        except Exception as e:
132                                self._error(e)
133                                returnValue=False
134                return returnValue
135        #def exportMdb
136
137        ###
138        #Generates the sql
139        #Input: pmb tableName
140        #Output: Array of sql sentences
141        ###
142        def _generateSql(self,destTable,abiesTable):
143                transformDict=self._checkTransformField(abiesTable)
144                origData=self.tableValuesDict[abiesTable]
145                fileName=destTable+".sql"
146                if destTable not in self.blacklist:
147                        f=open (fileName,'w')
148                for line in origData:
149                        strInsertValues=''
150                        for index in self.pmb_tables[destTable]:
151                                if index!='':
152                                        if transformDict:
153                                                if index in transformDict.keys():
154                                                        strTransform=transformDict[index]
155#                                                       self._debug("Transforming value "+str(line[index])+" index "+str(index)+" with "+strTransform)
156                                                        line[index]=eval(strTransform)
157                                        tmp=str(line[index]).strip("\n")
158                                        #Clean tmp field
159                                        tmp=tmp.replace('"',' ')
160                                        try:
161                                                int(tmp)
162                                        except:
163                                                tmp=tmp.lstrip(' ')
164                                                tmp=tmp.rstrip(' ')
165                                                tmp='"'+tmp+'"'
166                                                pass
167                                else:
168                                        tmp='""'
169                                strInsertValues=strInsertValues+tmp+','
170                        strInsertValues=strInsertValues[:-1]
171                        if destTable not in self.blacklist:
172                                f.write("Insert into "+destTable+" values ("+strInsertValues+");\n")
173                if destTable not in self.blacklist:
174                        f.close()
175        #def _generateSql
176
177        ###
178        #Loads a table from a file or a virtual table from a bunch of tables
179        #Input: Table name
180        ###
181        def _loadTable(self,tableName):
182                fileName=self.workDir+tableName+'.csv'
183                data=[]
184                if os.path.exists(fileName):
185                        try:
186                                f=open(fileName,'r')
187                                lines=f.readlines()
188                                f.close()
189                                for line in lines:
190                                        array=line.split('|||')
191                                        data.append(array)
192                        except Exception as e:
193                                self._error(e)
194                else: #Check in virtual dict
195                        if tableName in self.virtual_tables.keys():
196                                data=self._loadVirtualTable(tableName)
197                        else:
198                                self._error("Table "+tableName+" not found")
199
200                self.tableValuesDict[tableName]=data
201                if tableName in self.formatTables.keys():
202                        self.tableValuesDict[tableName]=self._checkTransformTables(tableName)
203        #def _loadTable
204
205        ###
206        #Loads a virtual table as described by virtual table's dict
207        #Input: Table name
208        #Output: Dataset (array of arrays) with the virtual table
209        ###
210        def _loadVirtualTable(self,tableName):
211                self._debug("Loading virtual table "+tableName)
212                data=[]
213                dataDict={}
214                if tableName in self.virtual_tables.keys():
215                        proceed=False
216                        for key,line in self.virtual_tables[tableName].items():
217#                               print (s)ourceData)
218#                               for key,line in sourceData.items():
219                                        if line.startswith('get'):
220                                                proceed=True
221                                                sourceIndex=key.split(' ')[1]
222                                                getFrom=line.split(' ')[1]
223                                                sourceIndex=getFrom.split('.')[1]
224                                                sourceTable=getFrom.split('.')[0]
225                                                dataDict[key]=self._funcGetValueFromTable(sourceTable,sourceIndex)
226                        if proceed:
227                                #Data is charged on the dataDict, time to populate data array
228                                maxLen=0
229                                for key in dataDict.keys():
230                                        columnLen=len(dataDict[key])
231                                        if columnLen>maxLen:
232                                                maxLen=columnLen
233                                index=0
234                                while index<maxLen:
235                                        dataLine=[]
236                                        for key in self.virtual_tables[tableName].keys():
237                                                arrayIndex=int(key.split(' ')[-1])
238                                                if key in dataDict.keys():
239                                                        dataLine.insert(arrayIndex,dataDict[key][index])
240                                                else:
241                                                        dataLine.insert(arrayIndex,'')
242                                        data.append(dataLine)
243                                        index=index+1
244                else:
245                        self._error("No source for virtual table "+tableName)
246                return(data)
247
248        ###
249        #Finds the pmb table related with an abies table
250        #Input: Table name in abies
251        #Output: pmb table
252        ###
253        def _getTableEquivalence(self,tableName):
254                pmbTable=None
255                for key in self.pmb_abies.keys():
256                        if tableName in self.pmb_abies[key]:
257                                pmbTable=key
258                                break
259                return pmbTable
260        #def _getTableEquivalence
261
262        ###
263        #Check if there's any transformation to apply to the fields of a table
264        #Input: Abies table name
265        #Output: Dict with field indexes as keys and transformations to apply as values
266        def     _checkTransformField(self,abiesTable):
267                transformDict={}
268                if abiesTable in self.formatFields.keys():
269                        transform=self.formatFields[abiesTable]
270                        self._debug("Transforming fields "+str(transform)+" in "+abiesTable)
271                        for key,line in transform.items():
272                                index=int(key.split(' ')[-1])
273                                if line.startswith('add'):
274                                        transformDict[index]=self._transformAdd(line,index)
275                                elif line.startswith('value'):
276                                        transformDict[index]=self._transformValue(line,index)
277                                elif line.startswith('concat'):
278                                        transformDict[index]=self._transformConcat(line,index)
279                                elif line.startswith('date'):
280                                        transformDict[index]=self._transformDate(line,index)
281                                elif line.startswith('inc'):
282                                        transformDict[index]=self._transformInc(line,index)
283                                elif line.startswith('get'):
284                                        transformDict[index]=self._transformGet(line,index)
285                                elif line.startswith('from'):
286                                        transformDict[index]=self._transformQuery(line,index,abiesTable)
287
288                self._debug("TransformDict: "+str(transformDict))
289                return transformDict
290        #def _checkTransformField
291
292        ###
293        #Transform routines, self-explaining
294        ###
295        def _transformAdd(self,line,index):
296                sourceIndex=line.split(' ')[1]
297                increment=line.split(' ')[-1]
298                returnValue='int(line['+sourceIndex+'])+'+increment
299                return(returnValue)
300
301        def _transformValue(self,line,index):
302                values=line.split(',')
303                tmpStr=''
304                for value in values:
305                        relation=value.split('=')
306                        sourceValue=relation[0].split(' ')[-1]
307                        destValue=relation[-1]
308                        tmpStr=tmpStr+str(destValue)+' if line['+str(index)+']=="'+str(sourceValue)+'" else '
309                try:
310                        int(destValue)
311                        returnValue='('+tmpStr+ '"'+str(destValue)+'")'
312                except:
313                        returnValue='('+tmpStr+ ''+str(destValue)+')'
314                return(returnValue)
315
316        def _transformConcat(self,line,index):
317                concat=line.split(' ')[-1]
318                concatArray=concat.split(',')
319                tmpStr=''
320                for concatField in concatArray:
321                        tmpStr=tmpStr+'line['+str(concatField)+']+'
322                returnValue=tmpStr[:-1]
323                return(returnValue)
324
325        def _transformDate(self,line,index):
326                dates=line.split(' ')
327                sourceFormat=dates[1]+' '+dates[2]
328                destFormat=dates[3]+' '+dates[4]
329                returnValue='self._funcDateTransform(line['+str(index)+'],"'+sourceFormat+'","'+destFormat+'")'
330                return(returnValue)
331
332        def _funcDateTransform(self,date,origFormat,destFormat):
333                date=date.replace('"','')
334                destFormat=destFormat.replace('"','')
335                returnValue=(datetime.datetime.strptime(date, origFormat).strftime(destFormat))
336                return(returnValue)
337               
338        def _transformInc(self,line,index):
339                increment=line.split(' ')
340                inc=increment[1]
341                base=0
342                if len(increment)==3:
343                        base=int(increment[2])
344                if self.tmpInc<base:
345                        self.tmpInc=base
346                returnValue='self._funcIncrementField('+inc+')'
347                return(returnValue)
348        ###
349        #Some values need a special transformation that requires a helper function.
350        #Those helper functions are the _func...
351        ###
352        def _funcIncrementField(self,inc):
353                self.tmpInc=self.tmpInc+int(inc)
354                returnValue=self.tmpInc
355                return(returnValue)
356
357        def _transformGet(self,line,index):
358                getFrom=line.split(' ')[-1]
359                getFromTable=getFrom.split('.')[0]
360                getFromIndex=getFrom.split('.')[-1]
361                returnValue='self._funcGetValueFromTable('+getFromTable+','+getFromIndex+')'
362                return(returnValue)
363
364        def _funcGetValueFromTable(self,table,index):
365                fileName=table+'.csv'
366                data=[]
367                index=int(index)
368                if os.path.exists(fileName):
369                        try:
370                                f=open(fileName,'r')
371                                lines=f.readlines()
372                                f.close()
373                                for line in lines:
374                                        array=line.split('|||')
375                                        data.append(array[index])
376                        except Exception as e:
377                                self._error(e)
378                else:
379                        self._error("No source table "+fileName+" available")
380                return(data)
381
382        def _transformQuery(self,line,index,tableName):
383                self._debug("Join field "+line)
384                transformDict=[]
385                arrayLine=line.split(' ')
386                sourceTableField=arrayLine[1]
387                joinFromTo=arrayLine[-1]
388                sourceTable=sourceTableField.split('.')[0]
389                sourceField=int(sourceTableField.split('.')[1])
390                joinFrom=joinFromTo.split('=')[0]
391                joinTo=joinFromTo.split('=')[1]
392                returnValue='self._funcGetValueFromQuery("'+tableName+'","'+sourceTable+'",line['+str(joinFrom)+'],'+str(joinTo)+','+str(sourceField)+')'
393                return(returnValue)
394
395        def _funcGetValueFromQuery(self,abiesTable,sourceTable,valueFrom,fieldTo,reqFieldIndex):
396                returnValue=''
397                valueFrom=valueFrom.strip("\n")
398                if sourceTable not in self.tableValuesDict:
399                        self._loadTable(sourceTable)
400                for row in self.tableValuesDict[sourceTable]:
401                                #                       print ("Comparing "+str(valueFrom)+" with "+str(row[fieldTo]))
402                        if valueFrom==str(row[fieldTo]).strip("\n"):
403                                returnValue=row[reqFieldIndex]
404                                break
405                return returnValue
406        #Transform fields functions
407
408        ###
409        #Check if there's any Transform to apply to a whole table
410        #Input: abies table
411        #Output: Dataset with the table
412        ###
413        def _checkTransformTables(self,tableName):
414                transformDict={}
415                if tableName in self.formatTables.keys():
416                        transform=self.formatTables[tableName]
417                        for key,line in transform.items():
418                                index=int(key.split(' ')[-1])
419                                if line.startswith('uniq'):
420                                        transformDict=self._transformTableUniq(tableName,index)
421                                if line.startswith('from'):
422                                        transformDict=self._transformTableJoin(tableName,index,line)
423                return transformDict
424        #def _checkTransformTamble
425
426        ###
427        #Function helpers for table transformation. Self-explaining
428        ###
429        def _transformTableUniq(self,tableName,index):
430                self._debug("Uniq items from index "+str(index))
431                transformDict=[]
432                for item in self.tableValuesDict[tableName]:
433                        if item not in transformDict:
434                                transformDict.append(item)
435                return transformDict
436
437        def _transformTableJoin(self,tableName,index,line):
438                self._debug("Join "+line)
439                transformDict=[]
440                arrayLine=line.split(' ')
441                sourceTableField=arrayLine[1]
442                joinFromTo=arrayLine[-1]
443                sourceTable=sourceTableField.split('.')[0]
444                sourceField=int(sourceTableField.split('.')[1])
445                joinFrom=joinFromTo.split('=')[0]
446                joinTo=joinFromTo.split('=')[1]
447                if sourceTable not in self.tableValuesDict:
448                        self._loadTable(sourceTable)
449                #Generate a dict with joinTo as index and required field as value
450                tmpDict={}
451                tmpIndex=int(joinTo)
452                for row in self.tableValuesDict[sourceTable]:
453                        rowIndex=row[tmpIndex]
454                        rowValue=row[sourceField]
455                        tmpDict.update({rowIndex:rowValue})
456
457                #Walk through origin table and insert values from sourceTableDict
458                tmpIndex=int(joinFrom)
459                for row in self.tableValuesDict[tableName]:
460                        rowIndex=row[tmpIndex]
461                        if rowIndex in tmpDict:
462                                row.insert(tmpIndex,tmpDict[rowIndex])
463                        else:
464                                row.insert(tmpIndex,'')
465                        transformDict.append(row)
466                return transformDict
467        #Table transformation function helpers
468
469### MAIN PROGRAM ###
470
471migration=abiesToPmb(sys.argv[1])
472result=migration.beginMigration()
473print(result)
474
475
476'''                             #-------------------#
477#Abrimos fichero csv
478#FICHERO se alimenta desde el array de ficheros
479f=open("TiposLector.csv","r")
480#Cargamos el array
481array=f.readlines()
482#Recorremos
483x=0
484#Diccionario nombre_tabla_pmb->array con inserts
485dictResult={"empr_categ":[]}
486for line in array:
487        campos=line.split('|||')
488        x=x+1
489        if x==1:
490                pass
491        else:
492                dictResult['empr_categ'].append('insert into empr_categ values('+campos[0]+','+campos[1])
493
494print (dictResult)
495'''
496
Note: See TracBrowser for help on using the repository browser.