|
- <%
- '=======================================================================================================================
- ' AUTOMAPPER CLASS
- '=======================================================================================================================
-
- 'Side Effects: Since src and target are passed ByRef to reduce unnecessary copying, if src is a recordset then the
- ' current record pointer is modified using src.MoveFirst and src.MoveNext. The end result is the current
- ' record pointer ends the operation at src.EOF.
-
- Class Automapper_Class
- Private m_src
- Private m_target
- Private m_statements
- Private m_statements_count
-
- Private Property Get Src : set Src = m_src : End Property
- Private Property Get Target : set Target = m_target : End Property
-
- Private Sub Class_Initialize
- m_statements = Array()
- m_statements_count = 0
- redim m_statements(m_statements_count)
- End Sub
-
- Private Sub ResetState
- m_statements_count = 0
- redim m_statements(m_statements_count)
- set m_src = Nothing
- set m_target = Nothing
- End Sub
-
- 'Maps all rs or object fields to corresponding fields in the specified class.
- Public Function AutoMap(src_obj, target_obj)
- Set AutoMap = FlexMap(src_obj, target_obj, empty)
- End Function
-
- 'Only maps fields specified in the field_names array (array of strings).
- 'If field_names is empty, attempts to map all fields from the passed rs or object.
- Public Function FlexMap(src_obj, target_obj, field_names)
- Set FlexMap = DynMap(src_obj, target_obj, field_names, empty)
- End Function
-
- 'Only maps fields specified in the field_names array (array of strings).
- 'If field_names is empty then src MUST be a recordset as it attempts to map all fields from the recordset.
- 'Since there is no reflection in vbscript, there is no way around this short of pseudo-reflection.
- Public Function DynMap(src_obj, target_obj, field_names, exprs)
- SetSource src_obj
- SetTarget target_obj
-
- dim field_name
- dim field_idx 'loop counter
-
- if IsEmpty(field_names) then 'map everything
- if typename(src_obj) = "Recordset" then
- for field_idx = 0 to src_obj.Fields.Count - 1
- field_name = src_obj.Fields.Item(field_idx).Name
- 'AddStatement field_name
- AddStatement BuildStatement(field_name)
- next
-
- elseif InStr(typename(src_obj), "Dictionary") > 0 then 'enables Scripting.Dictionary and IRequestDictionary for Request.Querystring and Request.Form
- for each field_name in src_obj
- AddStatement BuildStatement(field_name)
- next
-
- elseif not IsEmpty(src_obj.Class_Get_Properties) then
- dim props : props = src_obj.Class_Get_Properties
- for field_idx = 0 to ubound(props)
- field_name = props(field_idx)
- 'AddStatement field_name
- AddStatement BuildStatement(field_name)
- next
-
- else 'some invalid type of object
- Err.Raise 9, "Automapper.DynMap", "Cannot automatically map this source object. Expected recordset or object implementing Class_Get_Properties reflection, got: " & typename(src_obj)
- end if
-
- else 'map only specified fields
- for field_idx = lbound(field_names) to ubound(field_names)
- field_name = field_names(field_idx)
- 'AddStatement field_name
- AddStatement BuildStatement(field_name)
- next
- end if
-
- dim exprs_idx
-
- if not IsEmpty(exprs) then
- if typename(exprs) = "Variant()" then
- for exprs_idx = lbound(exprs) to ubound(exprs)
- 'field_name = exprs(exprs_idx)
- 'AddStatement field_name
- AddStatement exprs(exprs_idx)
- next
- else 'assume string or string-like default value
- AddStatement exprs
- end if
- end if
-
- 'Can't pre-join the statements because if one fails the rest of them fail too... :(
- 'dim joined_statements : joined_statements = Join(m_statements, " : ")
- 'put joined_statements
-
- 'suspend errors to prevent failing when attempting to map a field that does not exist in the class
- on error resume next
- dim stmt_idx
- for stmt_idx = 0 to ubound(m_statements)
- Execute m_statements(stmt_idx)
- next
- on error goto 0
-
- set DynMap = m_target
-
- ResetState
- End Function
-
-
- Private Sub SetSource(ByVal src_obj)
- set m_src = src_obj
- End Sub
-
- Private Sub SetTarget(ByVal target_obj)
- if typename(target_obj) = "String" then
- set m_target = eval("new " & target_obj)
- else
- set m_target = target_obj
- end if
- End Sub
-
-
- 'Builds a statement and adds it to the internal statements array
- Private Sub AddStatement(ByVal stmt)
- redim preserve m_statements(m_statements_count + 1)
- m_statements(m_statements_count) = stmt
- m_statements_count = m_statements_count + 1
- End Sub
-
- Private Function BuildStatement(ByVal field_name)
- dim result
- if typename(m_src) = "Recordset" or InStr(typename(m_src), "Dictionary") > 0 then
- result = "m_target." & field_name & " = m_src(""" & field_name & """)"
- else
- 'Funky magic...
- 'If src.field_name is an object, ensure the set statement is used
- if IsObject(eval("m_src." & field_name)) then
- result = "set "
- else
- 'result = "m_target." & field_name & " = m_src." & field_name
- end if
- result = result & " m_target." & field_name & " = m_src." & field_name
- end if
- BuildStatement = result
- End Function
- End Class
-
-
- Function Automapper()
- Set Automapper = new Automapper_Class
- End Function
- %>
|