View Javadoc

1   ////////////////////////////////////////////////////////////////////////////////
2   // MillScript: an Open Spice interpreter and batch website creation tool
3   // Copyright (C) 2001-2004 Open World Ltd
4   // Copyright (C) 2005 Kevin Rogers
5   //
6   // This file is part of MillScript.
7   //
8   // MillScript is free software; you can redistribute it and/or modify it under
9   // the terms of the GNU General Public License as published by the Free
10  // Software Foundation; either version 2 of the License, or (at your option)
11  // any later version.
12  //
13  // MillScript is distributed in the hope that it will be useful, but WITHOUT
14  // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
16  // more details.
17  //
18  // You should have received a copy of the GNU General Public License along with
19  // MillScript; if not, write to the Free Software Foundation, Inc., 59 Temple
20  // Place, Suite 330, Boston, MA  02111-1307  USA
21  ////////////////////////////////////////////////////////////////////////////////
22  package org.millscript.millscript.functions;
23  
24  import org.millscript.commons.util.EList;
25  import org.millscript.commons.util.EMap;
26  import org.millscript.commons.util.IList;
27  import org.millscript.commons.util.IMap;
28  import org.millscript.commons.util.ListIterator;
29  import org.millscript.commons.util.list.ELinkedList;
30  import org.millscript.commons.util.map.EHashMap;
31  import org.millscript.millscript.alert.Alerts;
32  import org.millscript.millscript.vm.Machine;
33  
34  /**
35   * This class implements the MillScript <code>joinByPrimaryKey</code> function.
36   */
37  public class JoinByPrimaryKeyFunction extends Function {
38  
39      /**
40       * @see org.millscript.millscript.functions.Function#apply(org.millscript.millscript.vm.Machine, int)
41       */
42      @Override
43      public void apply( final Machine mc, final int nargs ) {
44          checkNargs( mc, 3, nargs );
45          Object by = mc.popObject();
46          IList y = mc.popIList();
47          IList x = mc.popIList();
48          IMap ibpk = IndexByPrimaryKeyFunction.indexByPrimaryKey( y, by );
49          mc.pushObject( jbpk( x, ibpk, by ) );
50      }
51  
52      /**
53       * Returns the supplied data joined by the specified field. The data is
54       * supplied as a list of one set of data and a map containing the indexed
55       * other set of data.
56       *
57       * @param x the list of maps for one set of data
58       * @param map   the indexed other set of data
59       * @param by    the field to join by
60       * @return  a list of maps containing the two sets of data joined together
61       * @see IndexByPrimaryKeyFunction
62       */
63      @SuppressWarnings( "unchecked" )
64      static IList jbpk( final IList x, final IMap map, final Object by ) {
65          EList< IMap > result = new ELinkedList< IMap >();
66          ListIterator< ? > it = x.iterator( true );
67          while ( it.hasNext() ) {
68              // Select the next map in the list of maps
69              IMap recordX = (IMap)it.nextValue();
70              // Fetch the corresponding map from the indexed set 
71              IMap recordY = (IMap)map.get( recordX.get( by ) );
72              if ( recordY == null ) {
73                  throw(
74                      Alerts.eval(
75                          "Missing record",
76                          "When joining by primary key, there must be a record for each key"
77                      ).
78                      culprit( "key", by ).
79                      culprit( "record", recordX ).
80                      mishap()
81                  );
82              }
83              EMap< Object, Object > m = new EHashMap< Object, Object >( recordY );
84              m.insertAll( recordX );   //  x overrides y
85              result.addLast( m );
86          }
87          return result;
88      }
89  
90  }