diff --git a/src/client/app/actions/ciks.ts b/src/client/app/actions/ciks.ts new file mode 100644 index 000000000..3f7a9c78c --- /dev/null +++ b/src/client/app/actions/ciks.ts @@ -0,0 +1,51 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import { ActionType, Thunk, Dispatch, GetState } from '../types/redux/actions'; +import * as t from '../types/redux/ciks' +import { ciksApi } from '../utils/api'; + +export function requestCiksDetails(): t.RequestCiksDetailsAction { + return { type: ActionType.RequestCiksDetails }; +} + +export function receiveCiksDetails(data: t.CikData[]): t.ReceiveCiksDetailsAction { + return { type: ActionType.ReceiveCiksDetails, data }; +} + +export function confirmCiksFetchedOnce(): t.ConfirmCiksFetchedOneAction { + return { type: ActionType.ConfirmCiksFetchedOne }; +} + +export function fetchCiksData(): Thunk { + return async (dispatch: Dispatch, getState: GetState) => { + // make sure ciks is not being fetched + if (!getState().ciks.isFetching) { + // set isFetching to true + dispatch(requestCiksDetails()); + // retrieve ciks data from database + const ciks = await ciksApi.getCiksDetails(); + // update the state with the Cik details and set isFetching to false + dispatch(receiveCiksDetails(ciks)); + // If this is the first fetch, inform the store that the first fetch has been made + if (!getState().ciks.hasBeenFetchedOne) { + dispatch(confirmCiksFetchedOnce()); + } + } + } +} + +/** + * Fetch the ciks details from the database if they have not already been fetched once + */ +export function fetchCiksIfNeeded(): Thunk { + return async (dispatch: Dispatch, getState: GetState) => { + // If ciks have not been fetched once, call the fetchCiksData + if (!getState().ciks.hasBeenFetchedOne) { + dispatch(fetchCiksData()); + } + // If ciks have already been fetched, return a resolved promise + return Promise.resolve(); + } +} \ No newline at end of file diff --git a/src/client/app/components/InitializationComponent.tsx b/src/client/app/components/InitializationComponent.tsx index 144a7a85f..61070dfdb 100644 --- a/src/client/app/components/InitializationComponent.tsx +++ b/src/client/app/components/InitializationComponent.tsx @@ -8,7 +8,6 @@ import { useDispatch, useSelector } from 'react-redux'; import { State } from '../types/redux/state'; import { fetchMetersDetails, fetchMetersDetailsIfNeeded } from '../actions/meters'; import { fetchGroupsDetailsIfNeeded } from '../actions/groups'; -import { ConversionArray } from '../types/conversionArray'; import { fetchPreferencesIfNeeded } from '../actions/admin'; import { fetchMapsDetails } from '../actions/map'; import { fetchUnitsDetailsIfNeeded } from '../actions/units'; @@ -16,6 +15,7 @@ import { fetchConversionsDetailsIfNeeded } from '../actions/conversions'; import { Dispatch } from 'types/redux/actions'; import { Slide, ToastContainer } from 'react-toastify'; import 'react-toastify/dist/ReactToastify.css'; +import { fetchCiksIfNeeded } from '../actions/ciks'; /** * Initializes OED redux with needed details @@ -33,7 +33,7 @@ export default function InitializationComponent() { dispatch(fetchMapsDetails()); dispatch(fetchUnitsDetailsIfNeeded()); dispatch(fetchConversionsDetailsIfNeeded()); - ConversionArray.fetchPik(); + dispatch(fetchCiksIfNeeded()); }, []); // Rerender the route component if the user state changes diff --git a/src/client/app/components/conversion/EditConversionModalComponent.tsx b/src/client/app/components/conversion/EditConversionModalComponent.tsx index a00e6d8e2..b177e2f09 100644 --- a/src/client/app/components/conversion/EditConversionModalComponent.tsx +++ b/src/client/app/components/conversion/EditConversionModalComponent.tsx @@ -117,7 +117,7 @@ export default function EditConversionModalComponent(props: EditConversionModalC // If there is a difference between props and state, then a change was made // Side note, we could probably just set a boolean when any input i // Edit Conversion Validation: is not needed as no breaking edits can be made - const handleSaveChanges = () => { + const handleSaveChanges = async () => { // Close the modal first to avoid repeat clicks props.handleClose(); diff --git a/src/client/app/components/groups/CreateGroupModalComponent.tsx b/src/client/app/components/groups/CreateGroupModalComponent.tsx index 6d1023272..33a80e43e 100644 --- a/src/client/app/components/groups/CreateGroupModalComponent.tsx +++ b/src/client/app/components/groups/CreateGroupModalComponent.tsx @@ -25,7 +25,6 @@ import { UnitData } from '../../types/redux/units'; import { unitsCompatibleWithMeters, getMeterMenuOptionsForGroup, getGroupMenuOptionsForGroup, metersInChangedGroup } from '../../utils/determineCompatibleUnits'; -import { ConversionArray } from '../../types/conversionArray'; import { GPSPoint, isValidGPSInput } from '../../utils/calibration'; import { notifyUser, getGPSString } from '../../utils/input' import { tooltipBaseStyle } from '../../styles/modalStyle'; @@ -50,6 +49,8 @@ export default function CreateGroupModalComponent(props: CreateGroupModalCompone const groupsState = useSelector((state: State) => state.groups.byGroupID); // Unit state const unitsState = useSelector((state: State) => state.units.units); + // Cik state + const ciksState = useSelector((state: State) => state.ciks.ciks); // Check for admin status const currentUser = useSelector((state: State) => state.currentUser.profile); @@ -247,10 +248,10 @@ export default function CreateGroupModalComponent(props: CreateGroupModalCompone groupSelectOptions: possibleGroups }); } - // pik is needed since the compatible units is not correct until pik is available. // metersState normally does not change but can so include. // groupState can change if another group is created/edited and this can change ones displayed in menus. - }, [ConversionArray.pikAvailable(), metersState, groupsState, state.defaultGraphicUnit, state.deepMeters]); + // make sure ciksState is available. + }, [metersState, groupsState, state.defaultGraphicUnit, state.deepMeters, ciksState]); // Update compatible default graphic units set. useEffect(() => { @@ -283,8 +284,8 @@ export default function CreateGroupModalComponent(props: CreateGroupModalCompone } // If any of these change then it needs to be updated. // metersState normally does not change but can so include. - // pik is needed since the compatible units is not correct until pik is available. - }, [ConversionArray.pikAvailable(), metersState, state.deepMeters]); + // make sure ciksState is available. + }, [metersState, state.deepMeters, ciksState]); const tooltipStyle = { ...tooltipBaseStyle, diff --git a/src/client/app/components/groups/EditGroupModalComponent.tsx b/src/client/app/components/groups/EditGroupModalComponent.tsx index 050ef0f06..301935cbb 100644 --- a/src/client/app/components/groups/EditGroupModalComponent.tsx +++ b/src/client/app/components/groups/EditGroupModalComponent.tsx @@ -29,7 +29,6 @@ import { unitsCompatibleWithMeters, getMeterMenuOptionsForGroup, getGroupMenuOptionsForGroup, getCompatibilityChangeCase, GroupCase } from '../../utils/determineCompatibleUnits'; -import { ConversionArray } from '../../types/conversionArray'; import { GPSPoint, isValidGPSInput } from '../../utils/calibration'; import { notifyUser, getGPSString, nullToEmptyString } from '../../utils/input'; import { GroupDefinition } from '../../types/redux/groups'; @@ -60,6 +59,8 @@ export default function EditGroupModalComponent(props: EditGroupModalComponentPr // Meter state const metersState = useSelector((state: State) => state.meters.byMeterID); + // Cik state + const ciksState = useSelector((state: State) => state.ciks.ciks); // Group state used on other pages const globalGroupsState = useSelector((state: State) => state.groups.byGroupID); // Make a local copy of the group data so we can update during the edit process. @@ -352,10 +353,10 @@ export default function EditGroupModalComponent(props: EditGroupModalComponentPr groupSelectOptions: possibleGroups }); } - // pik is needed since the compatible units is not correct until pik is available. // metersState normally does not change but can so include. // globalGroupsState can change if another group is created/edited and this can change ones displayed in menus. - }, [ConversionArray.pikAvailable(), metersState, globalGroupsState, groupState.defaultGraphicUnit, groupState.deepMeters]); + // make sure ciksState is available. + }, [metersState, globalGroupsState, groupState.defaultGraphicUnit, groupState.deepMeters, ciksState]); // Update default graphic units set. useEffect(() => { @@ -387,12 +388,12 @@ export default function EditGroupModalComponent(props: EditGroupModalComponentPr }); } // If any of these change then it needs to be updated. - // pik is needed since the compatible units is not correct until pik is available. // metersState normally does not change but can so include. // If another group that is included in this group is changed then it must be redone // but we currently do a refresh so it is covered. It should still be okay if // the deep meters of this group are properly updated. - }, [ConversionArray.pikAvailable(), metersState, groupState.deepMeters]); + // Make sure ciksState is available. + }, [metersState, groupState.deepMeters, ciksState]); const tooltipStyle = { ...tooltipBaseStyle, diff --git a/src/client/app/components/meters/CreateMeterModalComponent.tsx b/src/client/app/components/meters/CreateMeterModalComponent.tsx index 221474dcb..714a01c82 100644 --- a/src/client/app/components/meters/CreateMeterModalComponent.tsx +++ b/src/client/app/components/meters/CreateMeterModalComponent.tsx @@ -19,7 +19,6 @@ import TimeZoneSelect from '../TimeZoneSelect'; import { GPSPoint, isValidGPSInput } from '../../utils/calibration'; import { UnitData } from '../../types/redux/units'; import { unitsCompatibleWithUnit } from '../../utils/determineCompatibleUnits'; -import { ConversionArray } from '../../types/conversionArray'; import { AreaUnitType } from '../../utils/getAreaUnitConversion'; import { notifyUser } from '../../utils/input' import { tooltipBaseStyle } from '../../styles/modalStyle'; @@ -122,6 +121,7 @@ export default function CreateMeterModalComponent(props: CreateMeterModalCompone // Dropdowns const [dropdownsState, setDropdownsState] = useState(dropdownsStateDefaults); + const ciksState = useSelector((state: State) => state.ciks.ciks); /* Create Meter Validation: Name cannot be blank @@ -332,9 +332,8 @@ export default function CreateMeterModalComponent(props: CreateMeterModalCompone compatibleUnits: new Set(compatibleUnits), incompatibleUnits: new Set(incompatibleUnits) }); - // If either unit or the status of pik changes then this needs to be done. - // pik is needed since the compatible units is not correct until pik is available. - }, [state.unitId, state.defaultGraphicUnit, ConversionArray.pikAvailable()]); + // cik is needed since the compatible units is not correct until cik is available. + }, [state.unitId, state.defaultGraphicUnit, ciksState]); const tooltipStyle = { ...tooltipBaseStyle, diff --git a/src/client/app/components/meters/EditMeterModalComponent.tsx b/src/client/app/components/meters/EditMeterModalComponent.tsx index 0a779c958..5159201f4 100644 --- a/src/client/app/components/meters/EditMeterModalComponent.tsx +++ b/src/client/app/components/meters/EditMeterModalComponent.tsx @@ -20,7 +20,6 @@ import TimeZoneSelect from '../TimeZoneSelect'; import { GPSPoint, isValidGPSInput } from '../../utils/calibration'; import { UnitData } from '../../types/redux/units'; import { unitsCompatibleWithUnit } from '../../utils/determineCompatibleUnits'; -import { ConversionArray } from '../../types/conversionArray'; import { AreaUnitType } from '../../utils/getAreaUnitConversion'; import { notifyUser, getGPSString, nullToEmptyString, noUnitTranslated } from '../../utils/input'; import { tooltipBaseStyle } from '../../styles/modalStyle'; @@ -119,6 +118,9 @@ export default function EditMeterModalComponent(props: EditMeterModalComponentPr // unit state const unitState = useSelector((state: State) => state.units.units); + // cik state + const ciksState = useSelector((state: State) => state.ciks.ciks); + /* Edit Meter Validation: Name cannot be blank @@ -176,6 +178,7 @@ export default function EditMeterModalComponent(props: EditMeterModalComponentPr state.maxDate, state.maxError ]); + /* End State */ // Reset the state to default values @@ -370,9 +373,9 @@ export default function EditMeterModalComponent(props: EditMeterModalComponentPr compatibleUnits: new Set(compatibleUnits), incompatibleUnits: new Set(incompatibleUnits) }); - // If either unit or the status of pik changes then this needs to be done. - // pik is needed since the compatible units is not correct until pik is available. - }, [state.unitId, state.defaultGraphicUnit, ConversionArray.pikAvailable()]); + // If either unit changes then this needs to be done. + // make sure ciksState is available. + }, [state.unitId, state.defaultGraphicUnit, ciksState]); // If you edit and return to this page then want to see the DB result formatted for users // for the readingFrequency. Since the update on save is to the global state, need to @@ -642,6 +645,7 @@ export default function EditMeterModalComponent(props: EditMeterModalComponentPr + {/* cumulativeResetStart input */} diff --git a/src/client/app/components/unit/CreateUnitModalComponent.tsx b/src/client/app/components/unit/CreateUnitModalComponent.tsx index 5353d4b41..b567cc09a 100644 --- a/src/client/app/components/unit/CreateUnitModalComponent.tsx +++ b/src/client/app/components/unit/CreateUnitModalComponent.tsx @@ -37,8 +37,7 @@ export default function CreateUnitModalComponent() { // The client code makes the id for the selected unit and default graphic unit be -99 // so it can tell it is not yet assigned and do the correct logic for that case. // The units API expects these values to be undefined on call so that the database can assign their values. - id: -99, - unitIndex: -99 + id: -99 } /* State */ diff --git a/src/client/app/components/unit/EditUnitModalComponent.tsx b/src/client/app/components/unit/EditUnitModalComponent.tsx index c60c1a29a..5f8f858e7 100644 --- a/src/client/app/components/unit/EditUnitModalComponent.tsx +++ b/src/client/app/components/unit/EditUnitModalComponent.tsx @@ -48,8 +48,7 @@ export default function EditUnitModalComponent(props: EditUnitModalComponentProp secInRate: props.unit.secInRate, suffix: props.unit.suffix, note: props.unit.note, - id: props.unit.id, - unitIndex: props.unit.unitIndex + id: props.unit.id } /* State */ diff --git a/src/client/app/reducers/ciks.ts b/src/client/app/reducers/ciks.ts new file mode 100644 index 000000000..238ee44d9 --- /dev/null +++ b/src/client/app/reducers/ciks.ts @@ -0,0 +1,36 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import { CiksAction, CiksState } from '../types/redux/ciks'; +import { ActionType } from '../types/redux/actions'; + +const defaultState: CiksState = { + hasBeenFetchedOne: false, + isFetching: false, + ciks: [] +} + +export default function ciks(state = defaultState, action: CiksAction) { + switch (action.type) { + case ActionType.ConfirmCiksFetchedOne: + return { + ...state, + hasBeenFetchedOne: true + }; + case ActionType.RequestCiksDetails: + return { + ...state, + isFetching: true + }; + case ActionType.ReceiveCiksDetails: + return { + ...state, + isFetching: false, + ciks: action.data + } + default: + return state; + } +} + diff --git a/src/client/app/reducers/index.ts b/src/client/app/reducers/index.ts index 5bd68cc69..c38cd2519 100644 --- a/src/client/app/reducers/index.ts +++ b/src/client/app/reducers/index.ts @@ -19,6 +19,7 @@ import unsavedWarning from './unsavedWarning'; import units from './units'; import conversions from './conversions'; import options from './options'; +import ciks from './ciks'; export default combineReducers({ @@ -39,5 +40,6 @@ export default combineReducers({ unsavedWarning, units, conversions, - options + options, + ciks }); diff --git a/src/client/app/types/conversionArray.ts b/src/client/app/types/conversionArray.ts deleted file mode 100644 index fdf1e3d78..000000000 --- a/src/client/app/types/conversionArray.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public -* License, v. 2.0. If a copy of the MPL was not distributed with this -* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -import { conversionArrayApi } from '../utils/api'; - -export class ConversionArray { - // Holds the pik array. - static pik: boolean[][]; - // True if pik array has been filled in. - static available = false; - - /** - * Gets pik from the server and stores in class variable pik for later use. - */ - static async fetchPik() { - this.available = false; - this.pik = await conversionArrayApi.getConversionArray(); - this.available = true; - } - - /** - * @returns returns true if pik has values and false if not yet filled in. - */ - static pikAvailable() { - return this.available; - } -} \ No newline at end of file diff --git a/src/client/app/types/redux/actions.ts b/src/client/app/types/redux/actions.ts index 3e4e14401..121199c7e 100644 --- a/src/client/app/types/redux/actions.ts +++ b/src/client/app/types/redux/actions.ts @@ -150,6 +150,10 @@ export enum ActionType { DeleteSubmittedConversion = 'DELETE_SUBMITTED_CONVERSION', DeleteConversion = 'DELETE_CONVERSION', ConfirmConversionsFetchedOnce = 'CONFIRM_CONVERSIONS_FETCHED_ONCE', + + RequestCiksDetails = 'REQUEST_CIKS_DETAILS', + ReceiveCiksDetails = 'RECEIVE_CIKS_DETAILS', + ConfirmCiksFetchedOne = 'CONFIRM_CIKS_FETCHED_ONE', } /** diff --git a/src/client/app/types/redux/ciks.ts b/src/client/app/types/redux/ciks.ts new file mode 100644 index 000000000..ecf95ba60 --- /dev/null +++ b/src/client/app/types/redux/ciks.ts @@ -0,0 +1,35 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import { ActionType } from './actions'; + +export interface RequestCiksDetailsAction { + type: ActionType.RequestCiksDetails; +} + +export interface ReceiveCiksDetailsAction { + type: ActionType.ReceiveCiksDetails; + data: CikData[]; +} + +export interface ConfirmCiksFetchedOneAction { + type: ActionType.ConfirmCiksFetchedOne; +} + +export type CiksAction = RequestCiksDetailsAction +| ReceiveCiksDetailsAction +| ConfirmCiksFetchedOneAction; + +export interface CikData { + meterUnitId: number; + nonMeterUnitId: number; + slope: number; + intercept: number; +} + +export interface CiksState { + hasBeenFetchedOne: boolean; + isFetching: boolean; + ciks: CikData[]; +} diff --git a/src/client/app/types/redux/state.ts b/src/client/app/types/redux/state.ts index 40f4c0fa6..bd16a06a6 100644 --- a/src/client/app/types/redux/state.ts +++ b/src/client/app/types/redux/state.ts @@ -17,6 +17,7 @@ import { UnsavedWarningState } from './unsavedWarning'; import { UnitsState } from './units'; import { ConversionsState } from './conversions'; import { OptionsState } from './options'; +import { CiksState } from './ciks'; export interface State { meters: MetersState; @@ -36,4 +37,5 @@ export interface State { units: UnitsState; conversions: ConversionsState; options: OptionsState; + ciks: CiksState; } diff --git a/src/client/app/types/redux/units.ts b/src/client/app/types/redux/units.ts index 523bed286..e81a71d51 100644 --- a/src/client/app/types/redux/units.ts +++ b/src/client/app/types/redux/units.ts @@ -70,7 +70,6 @@ export interface UnitData { unitRepresent: UnitRepresentType; secInRate: number; typeOfUnit: UnitType; - unitIndex: number; suffix: string; displayable: DisplayableType; preferredDisplay: boolean; @@ -84,7 +83,6 @@ export interface UnitEditData { unitRepresent: string; secInRate: number; typeOfUnit: UnitType; - unitIndex: number; suffix: string; displayable: DisplayableType; preferredDisplay: boolean; diff --git a/src/client/app/utils/api/CiksApi.ts b/src/client/app/utils/api/CiksApi.ts new file mode 100644 index 000000000..42964008a --- /dev/null +++ b/src/client/app/utils/api/CiksApi.ts @@ -0,0 +1,20 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +import ApiBackend from './ApiBackend'; +import { CikData } from 'types/redux/ciks'; + +export default class CiksApi { + private readonly backend: ApiBackend; + + constructor(backend: ApiBackend) { + this.backend = backend; + } + + public async getCiksDetails(): Promise { + return await this.backend.doGetRequest('/api/ciks'); + } +} diff --git a/src/client/app/utils/api/index.ts b/src/client/app/utils/api/index.ts index 237e042ad..4ce030f3b 100644 --- a/src/client/app/utils/api/index.ts +++ b/src/client/app/utils/api/index.ts @@ -18,6 +18,7 @@ import LogsApi from './LogsApi'; import UnitsApi from './unitsApi'; import ConversionsApi from './ConversionsApi'; import ConversionArrayApi from './ConversionArrayApi'; +import CiksApi from './CiksApi'; const apiBackend = new ApiBackend(); @@ -35,6 +36,7 @@ const versionApi = new VersionApi(apiBackend); const conversionArrayApi = new ConversionArrayApi(apiBackend); const unitsApi = new UnitsApi(apiBackend); const conversionsApi = new ConversionsApi(apiBackend); +const ciksApi = new CiksApi(apiBackend); export { @@ -50,5 +52,6 @@ export { uploadCSVApi, conversionArrayApi, unitsApi, - conversionsApi + conversionsApi, + ciksApi }; diff --git a/src/client/app/utils/determineCompatibleUnits.ts b/src/client/app/utils/determineCompatibleUnits.ts index 61a6b6de8..d2721be3c 100644 --- a/src/client/app/utils/determineCompatibleUnits.ts +++ b/src/client/app/utils/determineCompatibleUnits.ts @@ -5,8 +5,6 @@ import { store } from '../store'; import * as _ from 'lodash'; import { MeterData } from '../types/redux/meters'; -import { ConversionArray } from '../types/conversionArray'; -import { UnitData, UnitType } from '../types/redux/units'; import { GroupDefinition, GroupEditData } from '../types/redux/groups'; import { DataType } from '../types/Datasources'; import { State } from '../types/redux/state'; @@ -62,75 +60,29 @@ export function unitsCompatibleWithMeters(meters: Set): Set { /** * Returns a set of units ids that are compatible with a specific unit id. - * @param unitId The unit id. - * @returns Set of units ids that are compatible with specified unit id. + * @param unitId The unit id + * @returns a set of compatible unit ids */ export function unitsCompatibleWithUnit(unitId: number): Set { - // unitSet starts as an empty set. + // access the global state + const state = store.getState(); const unitSet = new Set(); + // get all ciks data + const globalCiksState = state.ciks.ciks; // If unit was null in the database then -99. This means there is no unit // so nothing is compatible with it. Skip processing and return empty set at end. - // Do same if pik is not yet available. - if (unitId != -99 && ConversionArray.pikAvailable()) { - // The Pik array. - const pik = ConversionArray.pik; - // Get the row index in Pik of this unit. - const row = pRowFromUnit(unitId); - // The compatible units are all columns with true for Pik where i = row. - // Loops over all columns of Pik in row. - for (let k = 0; k < pik[0].length; ++k) { - if (pik[row][k]) { - // unit at index k is compatible with meter unit so add to set. - // Convert index in Pik to unit id. - unitSet.add(unitFromPColumn(k)); + if (unitId !== -99) { + // loop through each cik to find ones whose meterUnitId equals unitId param + // then add the corresponding nonMeterUnitId to the unitSet + for (const cik of globalCiksState) { + if (cik.meterUnitId === unitId) { + unitSet.add(cik.nonMeterUnitId); } } } return unitSet; } -/** - * Returns the row index in Pik for a meter unit. - * @param unitId The unit id. - * @returns The row index in Pik for given meter unit. - */ -export function pRowFromUnit(unitId: number): number { - const state = store.getState(); - const unit = _.find(state.units.units, function (o: UnitData) { - // Since this is the row index, type of unit must be meter. - return o.id == unitId && o.typeOfUnit == UnitType.meter; - }) as UnitData; - return unit.unitIndex; -} - -/** - * Returns the unit id given the row in Pik. - * @param row The row to find the associated unit. - * @returns The unit id given the row in Pik units. - */ -export function unitFromPRow(row: number): number { - const state = store.getState(); - const unit = _.find(state.units.units, function (o: UnitData) { - // Since the given unitIndex is a row index, the unit type must be meter. - return o.unitIndex == row && o.typeOfUnit == UnitType.meter; - }) as UnitData; - return unit.id; -} - -/** - * Returns the unit id given the column in Pik. - * @param column The column to find the associated unit. - * @returns The unit id given the column in Pik. - */ -export function unitFromPColumn(column: number): number { - const state = store.getState(); - const unit = _.find(state.units.units, function (o: UnitData) { - // Since the given unitIndex is a column index, the unit type must be different from meter. - return o.unitIndex == column && o.typeOfUnit != UnitType.meter; - }) as UnitData; - return unit.id; -} - /** * Returns the set of meters's ids associated with the groupId used where Redux * state is accurate for all groups. diff --git a/src/client/app/utils/input.ts b/src/client/app/utils/input.ts index bd86b3342..a63a83b65 100644 --- a/src/client/app/utils/input.ts +++ b/src/client/app/utils/input.ts @@ -88,7 +88,6 @@ export const NoUnit: UnitData = { unitRepresent: UnitRepresentType.quantity, secInRate: 99, typeOfUnit: UnitType.unit, - unitIndex: -99, suffix: '', displayable: DisplayableType.none, preferredDisplay: false, diff --git a/src/server/app.js b/src/server/app.js index 27341a41f..2524ccf08 100644 --- a/src/server/app.js +++ b/src/server/app.js @@ -32,6 +32,7 @@ const csv = require('./routes/csv'); const conversionArray = require('./routes/conversionArray'); const units = require('./routes/units'); const conversions = require('./routes/conversions'); +const ciks = require('./routes/ciks'); // Limit the rate of overall requests to OED // Note that the rate limit may make the automatic test return the value of 429. In that case, the limiters below need to be increased. @@ -90,6 +91,7 @@ app.use('/api/csv', csv); app.use('/api/conversion-array', conversionArray); app.use('/api/units', units); app.use('/api/conversions', conversions); +app.use('/api/ciks', ciks); app.use(express.static(path.join(__dirname, '..', 'client', 'public'))); const router = express.Router(); diff --git a/src/server/migrations/1.0.0-1.1.0/index.js b/src/server/migrations/1.0.0-1.1.0/index.js index 79dd7f94d..cf4993ab4 100644 --- a/src/server/migrations/1.0.0-1.1.0/index.js +++ b/src/server/migrations/1.0.0-1.1.0/index.js @@ -14,5 +14,8 @@ module.exports = { await db.none(sqlFile('../migrations/1.0.0-1.1.0/sql/preferences/add_preferences_pipeline_checks.sql')); await db.none(sqlFile('../migrations/1.0.0-1.1.0/sql/preferences/add_graph_type.sql')); await db.none(sqlFile('../migrations/1.0.0-1.1.0/sql/preferences/add_preferences_help_url.sql')); + // It should not matter but first rename cik and then do units. + await db.none(sqlFile('../migrations/1.0.0-1.1.0/sql/cik/alter_cik_table.sql')); + await db.none(sqlFile('../migrations/1.0.0-1.1.0/sql/units/alter_units_table.sql')); } }; diff --git a/src/server/migrations/1.0.0-1.1.0/sql/cik/alter_cik_table.sql b/src/server/migrations/1.0.0-1.1.0/sql/cik/alter_cik_table.sql new file mode 100644 index 000000000..29e7c58a8 --- /dev/null +++ b/src/server/migrations/1.0.0-1.1.0/sql/cik/alter_cik_table.sql @@ -0,0 +1,17 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +-- Since don't want the values and no foreign keys, drop and recreate cik. +DROP TABLE cik; + +CREATE TABLE IF NOT EXISTS cik ( + source_id INTEGER REFERENCES units(id), + destination_id INTEGER REFERENCES units(id), + slope FLOAT, + intercept FLOAT, + PRIMARY KEY (source_id, destination_id) +); + +-- TODO It is important that a redoCik is done after this to recreate cik. +-- MUST ADD THIS TO THE 1.1 MIGRATION. diff --git a/src/server/sql/unit/get_by_unit_index_unit.sql b/src/server/migrations/1.0.0-1.1.0/sql/units/alter_units_table.sql similarity index 69% rename from src/server/sql/unit/get_by_unit_index_unit.sql rename to src/server/migrations/1.0.0-1.1.0/sql/units/alter_units_table.sql index 539b68bed..3f33f8f6a 100644 --- a/src/server/sql/unit/get_by_unit_index_unit.sql +++ b/src/server/migrations/1.0.0-1.1.0/sql/units/alter_units_table.sql @@ -2,5 +2,6 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -SELECT id FROM units -WHERE type_of_unit = 'unit'::unit_type AND unit_index = ${unitIndex}; \ No newline at end of file +ALTER TABLE units + DROP COLUMN IF EXISTS unit_index +; diff --git a/src/server/models/Cik.js b/src/server/models/Cik.js index 7fd0128bd..c32eaf033 100644 --- a/src/server/models/Cik.js +++ b/src/server/models/Cik.js @@ -11,6 +11,19 @@ const sqlFile = database.sqlFile; * [0]: is slope, [1]: is intercept, [2]: is not used here. */ class Cik { + /** + * @param {*} meterUnitId The id of the meter unit. + * @param {*} nonMeterUnitId The id of the non meter unit. + * @param {*} slope The slope of the conversion. + * @param {*} intercept The intercept of the conversion. + */ + constructor(meterUnitId, nonMeterUnitId, slope, intercept) { + this.meterUnitId = meterUnitId; + this.nonMeterUnitId = nonMeterUnitId; + this.slope = slope; + this.intercept = intercept; + } + /** * Returns a promise to create the cik table. * @param {*} conn The connection to use. @@ -20,6 +33,25 @@ class Cik { return conn.none(sqlFile('cik/create_cik_table.sql')); } + /** + * Create a new Cik object from row's data. + * @param {*} row The row from which Cik will be created. + * @returns the created Cik object + */ + static mapRow(row) { + return new Cik(row.meter_unit_id, row.non_meter_unit_id, row.slope, row.intercept); + } + + /** + * Get all Cik objects + * @param {*} conn The database connection to use. + * @returns all Cik objects + */ + static async getAll(conn) { + const rows = await conn.any(sqlFile('cik/get_cik.sql')); + return rows.map(Cik.mapRow); + } + /** * Inserts each element of the array with an actual conversion into the cik table. * The current values in the table are removed first. @@ -32,41 +64,15 @@ class Cik { // Remove all the current values in the table. await conn.none(sqlFile('cik/delete_all_conversions.sql')); - // Loop over the rows and columns of the cik array. - for (let row = 0; row < cik.length; ++row) { - for (let column = 0; column < cik[row].length; ++column) { - // If there is a conversion then insert it into the cik table in database. - // In principle need to check [0] and [1] but they should both be the same - // and only one checked as in other parts of the code. - if (!isNaN(cik[row][column][0])) { - await conn.none(sqlFile('cik/insert_new_conversion.sql'), { - rowIndex: row, - columnIndex: column, - slope: cik[row][column][0], - intercept: cik[row][column][1] - }); - } - } - } - } - - /** - * Returns Pik array based on Cik values in the database. - */ - static async getPik(conn) { - // Get the max index for pik rows and columns. Length is one greater. - let temp; - temp = await conn.one(sqlFile('unit/get_max_meter_row_index.sql')); - const numRows = temp.max + 1; - temp = await conn.one(sqlFile('unit/get_max_non_meter_row_index.sql')); - const numColumns = temp.max + 1; - // Fill the Pik with false values. - let pik = new Array(numRows).fill(0).map(() => new Array(numColumns).fill(false)); - // Get all the Cik values from the database. - const rows = await conn.any(sqlFile('cik/get_all_conversions.sql')); - // pik is true if there is a conversion for cik. - rows.map(row => { pik[row.row_index][row.column_index] = true; }); - return pik; + // Loop over all conversions in cik array and insert each in DB. + cik.forEach(async (conversion) => { + await conn.none(sqlFile('cik/insert_new_conversion.sql'), { + sourceId: conversion.source, + destinationId: conversion.destination, + slope: conversion.slope, + intercept: conversion.intercept + }); + }); } } diff --git a/src/server/models/Meter.js b/src/server/models/Meter.js index 0fe791f65..758210541 100644 --- a/src/server/models/Meter.js +++ b/src/server/models/Meter.js @@ -196,20 +196,6 @@ class Meter { return rows.map(Meter.mapRow); } - /** - * For the given meter id, gets the associated unitId. - * Then, returns the unitIndex (the row/column id in the Cik/Pik table) of that unitId. - * @param {*} meterId The meter id. - * @param {*} conn The connection to use. - * @returns {Promise.} - */ - static async getUnitIndex(meterId, conn) { - const resp = await conn.one(sqlFile('meter/get_unit_id.sql'), { meterId: meterId }); - const unitId = resp.unit_id; - const unit = await Unit.getById(unitId, conn); - return unit.unitIndex; - } - /** * Returns all meters where unitId is not null. * @param {*} conn The connection to be used. diff --git a/src/server/models/Unit.js b/src/server/models/Unit.js index f1056c7fc..a502ad08e 100644 --- a/src/server/models/Unit.js +++ b/src/server/models/Unit.js @@ -14,20 +14,18 @@ class Unit { * @param {*} unitRepresent Tells how the data is fetched for readings (only need for meter type unit). * @param {*} secInRate The number of seconds in the unit associated with flow (rate) units. * @param {*} typeOfUnit This unit's type. Can be meter, unit, or suffix. - * @param {*} unitIndex The unique number for row/column index in conversion table for this unit. * @param {*} suffix This unit's suffix. * @param {*} displayable Can be none, all, or admin. Restrict the type of user that can see this unit. * @param {*} preferredDisplay True if this unit is always displayed. If not, the user needs to ask to see (for future enhancement). * @param {*} note Note about this unit. */ - constructor(id, name, identifier = name, unitRepresent, secInRate = 3600, typeOfUnit, unitIndex, suffix = '', displayable, preferredDisplay, note) { + constructor(id, name, identifier = name, unitRepresent, secInRate = 3600, typeOfUnit, suffix = '', displayable, preferredDisplay, note) { this.id = id; this.name = name; this.identifier = identifier; this.unitRepresent = unitRepresent; this.secInRate = secInRate; this.typeOfUnit = typeOfUnit; - this.unitIndex = unitIndex; this.suffix = suffix; this.displayable = displayable; this.preferredDisplay = preferredDisplay; @@ -41,7 +39,7 @@ class Unit { */ static mapRow(row) { return new Unit(row.id, row.name, row.identifier, row.unit_represent, row.sec_in_rate, - row.type_of_unit, row.unit_index, row.suffix, row.displayable, row.preferred_display, row.note); + row.type_of_unit, row.suffix, row.displayable, row.preferred_display, row.note); } /** @@ -184,29 +182,6 @@ class Unit { return row === null ? null : Unit.mapRow(row); } - /** - * Returns the associated id of type meter for the given unitIndex. - * @param {*} unitIndex The unit's index. - * @param {*} conn The connection to use. - * @returns {Promise.} - */ - static async getByUnitIndexMeter(unitIndex, conn) { - const resp = await conn.one(sqlFile('unit/get_by_unit_index_meter.sql'), { unitIndex: unitIndex }); - return resp.id; - } - - // TODO: Returns a special value if it doesn't exist - /** - * Returns the associated id of type unit for the given unitIndex. - * @param {*} unitIndex The unit's index. - * @param {*} conn The connection to use. - * @returns {Promise.} - */ - static async getByUnitIndexUnit(unitIndex, conn) { - const resp = await conn.oneOrNone(sqlFile('unit/get_by_unit_index_unit.sql'), { unitIndex: unitIndex }); - return resp === null ? null : resp.id; - } - /** * Returns a promise to update an existing unit in the database. * @param {*} conn The connection to use. diff --git a/src/server/routes/ciks.js b/src/server/routes/ciks.js new file mode 100644 index 000000000..5eabee2f8 --- /dev/null +++ b/src/server/routes/ciks.js @@ -0,0 +1,34 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const express = require('express'); +const { log } = require('../log'); +const { getConnection } = require('../db'); +const Cik = require('../models/Cik'); + +const router = express.Router(); + +module.exports = router; + +function formatCikForResponse(item) { + return { + meterUnitId: item.meterUnitId, + nonMeterUnitId: item.nonMeterUnitId, + slope: item.slope, + intercept: item.intercept + } +} + +/** + * Router for getting all ciks. + */ +router.get('/', async (req, res) => { + const conn = getConnection(); + try { + const rows = await Cik.getAll(conn); + res.json(rows.map(formatCikForResponse)); + } catch (err) { + log.error(`Error while performing GET ciks details query: ${err}`); + } +}); \ No newline at end of file diff --git a/src/server/routes/conversionArray.js b/src/server/routes/conversionArray.js index 229940c6b..fe2f48920 100644 --- a/src/server/routes/conversionArray.js +++ b/src/server/routes/conversionArray.js @@ -3,27 +3,12 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ const express = require('express'); -const { log } = require('../log'); const { getConnection } = require('../db'); -const { createPik, redoCik } = require('../services/graph/redoCik'); +const { redoCik } = require('../services/graph/redoCik'); const { refreshAllReadingViews } = require('../services/refreshAllReadingViews'); const router = express.Router(); -/** - * Route for getting the conversion array. - */ -router.get('/', async (req, res) => { - const conn = getConnection(); - try { - // Creates the Pik array which is true if there is a conversion in Cik. - const pik = await createPik(conn); - res.json(pik); - } catch (err) { - log.error(`Error while performing GET conversion array query: ${err}`, err); - } -}); - /** * Route for redoing Cik and/or refreshing reading views. */ diff --git a/src/server/routes/conversions.js b/src/server/routes/conversions.js index 31b548835..7c5a1f44d 100644 --- a/src/server/routes/conversions.js +++ b/src/server/routes/conversions.js @@ -1,6 +1,6 @@ /* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ const express = require('express'); const { log } = require('../log'); @@ -69,7 +69,7 @@ router.post('/edit', async (req, res) => { const validatorResult = validate(req.body, validConversion); if (!validatorResult.valid) { log.warn(`Got request to edit conversions with invalid conversion data, errors: ${validatorResult.errors}`); - failure(res, 400, `Got request to edit conversions with invalid conversion data, errors: ${validatorResult.errors}`); + failure(res, 400, `Got request to edit conversions with invalid conversion data, errors: ${validatorResult.errors}`); } else { const conn = getConnection(); try { @@ -122,7 +122,7 @@ router.post('/addConversion', async (req, res) => { const validatorResult = validate(req.body, validConversion); if (!validatorResult.valid) { log.error(`Got request to insert conversion with invalid conversion data, errors: ${validatorResult.errors}`); - failure(res, 400, `Got request to insert conversion with invalid conversion data. Error(s): ${validatorResult.errors}`); + failure(res, 400, `Got request to insert conversion with invalid conversion data. Error(s): ${validatorResult.errors}`); } else { const conn = getConnection(); try { @@ -140,7 +140,7 @@ router.post('/addConversion', async (req, res) => { res.sendStatus(200); } catch (err) { log.error(`Error while inserting new conversion with error(s): ${err}`); - failure(res, 500, `Error while inserting new conversion with errors(s): ${err}`); + failure(res, 500, `Error while inserting new conversion with errors(s): ${err}`); } } }); @@ -171,7 +171,7 @@ router.post('/delete', async (req, res) => { const validatorResult = validate(req.body, validConversion); if (!validatorResult.valid) { log.warn(`Got request to delete conversions with invalid conversion data, errors: ${validatorResult.errors}`); - failure(res, 400, `Got request to delete conversions with invalid conversion data. Error(s): ${validatorResult.errors}`); + failure(res, 400, `Got request to delete conversions with invalid conversion data. Error(s): ${validatorResult.errors}`); } else { const conn = getConnection(); try { @@ -180,7 +180,7 @@ router.post('/delete', async (req, res) => { await Conversion.delete(req.body.sourceId, req.body.destinationId, conn); } catch (err) { log.error(`Error while deleting conversion with error(s): ${err}`); - failure(res, 500, `Error while deleting conversion with errors(s): ${err}`); + failure(res, 500, `Error while deleting conversion with errors(s): ${err}`); } success(res, `Successfully deleted conversion ${req.body.sourceId} -> ${req.body.destinationId}`); } diff --git a/src/server/routes/units.js b/src/server/routes/units.js index fd1dc1354..55728d106 100644 --- a/src/server/routes/units.js +++ b/src/server/routes/units.js @@ -15,7 +15,7 @@ const router = express.Router(); function formatUnitForResponse(item) { return { id: item.id, name: item.name, identifier: item.identifier, unitRepresent: item.unitRepresent, - secInRate: item.secInRate, typeOfUnit: item.typeOfUnit, unitIndex: item.unitIndex, suffix: item.suffix, + secInRate: item.secInRate, typeOfUnit: item.typeOfUnit, suffix: item.suffix, displayable: item.displayable, preferredDisplay: item.preferredDisplay, note: item.note }; } @@ -178,7 +178,6 @@ router.post('/addUnit', async (req, res) => { req.body.unitRepresent, req.body.secInRate, req.body.typeOfUnit, - undefined, // initIndex req.body.suffix, req.body.displayable, req.body.preferredDisplay, diff --git a/src/server/services/graph/createConversionArrays.js b/src/server/services/graph/createConversionArrays.js index 7eddaadb6..c67243809 100644 --- a/src/server/services/graph/createConversionArrays.js +++ b/src/server/services/graph/createConversionArrays.js @@ -2,36 +2,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +const { SemicolonPreference } = require('typescript'); const Unit = require('../../models/Unit'); const { getPath } = require('./createConversionGraph'); const { pathConversion } = require('./pathConversion'); -/** - * For each unit in the list, assigns its index to the conversion table. - * For source units, the index is the row id. - * For destination units, the index is the column id. - * @param {*} units The list of units. - * @param {*} conn The connection to use. - */ -async function assignIndex(units, conn) { - let id = 0; - // The old indices may cause conflicts while we are assigning new ones. - // Therefore, we need to reset them to null first. - // TODO: Note that while Cik is being recreated, requests may return null values. - for (let unit of units) { - if (unit.unitIndex !== null) { - unit.unitIndex = null; - await unit.update(conn); - } - } - // Assigns new indices. - for (let unit of units) { - unit.unitIndex = id; - id += 1; - await unit.update(conn); - } -} - /** * Returns the Cik which gives the slope, intercept and suffix name between each meter and unit * where it is NaN, Nan, '' if no conversion. @@ -54,21 +29,17 @@ async function createCikArray(graph, conn) { // since those cannot be graphed. The original unit with a suffix string is excluded by OED during // processing of suffix units. // The final consideration is how much including the extra items will cost. The larger array should not impact - // the speed of looking up an item in Cik or Pik. Sending Pik to the client will be larger but note that if - // there are 30 meter units and 100 unit/suffix units then Pik has 3000 items of type boolean. This will + // the speed of looking up an item in Cik. Sending Cik to the client will be larger but note that if + // there are 30 meter units and 100 unit/suffix units then Cik has 3000 items. This will // not be large, esp. compared to the rest of the startup payload of code. Thus, including all the // units should still be very efficient and the bytes saved by doing all the extra work above will be small. const sources = await Unit.getTypeMeter(conn); // This excludes units that have displayable none since cannot be graphed. const destinations = (await Unit.getTypeUnit(conn)).concat(await Unit.getTypeSuffix(conn)); // Size of each of these. - const numSources = sources.length; - const numDestination = destinations.length; - // Create an array to hold the values. Each entry will have double slope, double intercept, and string suffix. - // [NaN, NaN, ''] means that there is no conversion. - let c = new Array(numSources).fill(0).map(() => new Array(numDestination).fill([NaN, NaN, ''])); - await assignIndex(sources, conn); - await assignIndex(destinations, conn); + // Create an array to hold the values. Each entry will have integer souce it, integer destination id, double slope, + // double intercept, and string suffix. + const c = []; for (const source of sources) { for (const destination of destinations) { const sourceId = source.id; @@ -78,13 +49,13 @@ async function createCikArray(graph, conn) { // Check if the path exists. // If not, we will do nothing since the array has been initialized with [Nan, Nan, '']. if (path !== null) { - const [slope, intercept, suffix] = await pathConversion(path, conn); + const [slope, intercept] = await pathConversion(path, conn); // All suffix units were dealt in src/server/services/graph/handleSuffixUnits.js // so all units with suffix have displayable of none. // This means this path has a suffix of "" (empty) so it does not matter. // The name of any unit associated with a suffix was already set correctly. // Thus, we can just use the destination identifier as the unit name. - c[source.unitIndex][destination.unitIndex] = [slope, intercept, destination.identifier]; + c.push({ source: sourceId, destination: destinationId, slope: slope, intercept: intercept }); } } } @@ -94,29 +65,6 @@ async function createCikArray(graph, conn) { return c; } -/** - * Returns the Pik array which is true if there is a conversion in Cik. - * @param {*} c The Cik array. - * @returns - */ -function createPikArray(c) { - // The number of sources and destinations. - const numSources = c.length; - const numDestination = c[0].length; - let p = new Array(numSources).fill(0).map(() => new Array(numDestination).fill(true)); - for (let i = 0; i < numSources; ++i) { - for (let j = 0; j < numDestination; ++j) { - // If the conversion exists, we do nothing since Pij has been initialized with true. - // If not, we need to set Pij to false. - if (isNaN(c[i][j][0])) { - p[i][j] = false; - } - } - } - return p; -} - module.exports = { - createCikArray, - createPikArray -} \ No newline at end of file + createCikArray +} diff --git a/src/server/services/graph/handleSuffixUnits.js b/src/server/services/graph/handleSuffixUnits.js index 0db9def46..df7b1ed47 100644 --- a/src/server/services/graph/handleSuffixUnits.js +++ b/src/server/services/graph/handleSuffixUnits.js @@ -26,7 +26,7 @@ async function addNewUnitAndConversion(sourceId, destinationId, slope, intercept // Note the admin can later change identifier, displayable and preferredDisplay to something else // since OED does not recreate the unit if it exists so those changes will stay. const newUnit = new Unit(undefined, unitName, unitIdentifier, destinationUnit.unitRepresent, sourceUnit.secInRate, - Unit.unitType.SUFFIX, undefined, '', destinationUnit.displayable, destinationUnit.preferredDisplay, 'suffix unit created by OED'); + Unit.unitType.SUFFIX, '', destinationUnit.displayable, destinationUnit.preferredDisplay, 'suffix unit created by OED'); await newUnit.insert(conn); // Create the conversion from the prefix unit to this new unit. diff --git a/src/server/services/graph/redoCik.js b/src/server/services/graph/redoCik.js index fefe8a55c..3a4f9cb69 100644 --- a/src/server/services/graph/redoCik.js +++ b/src/server/services/graph/redoCik.js @@ -24,14 +24,6 @@ async function redoCik(conn) { await Cik.insert(cik, conn); } -/** - * Uses the cik table to create a Pik array and return it. - */ -async function createPik(conn) { - pik = await Cik.getPik(conn); - return pik; -} - /** * Needed to call from npm run. Give new name so hopefully won't use in regular code. */ @@ -44,6 +36,5 @@ async function updateCikAndViews() { module.exports = { redoCik, - createPik, updateCikAndViews }; diff --git a/src/server/sql/cik/create_cik_table.sql b/src/server/sql/cik/create_cik_table.sql index 9feed468b..c36e43e31 100644 --- a/src/server/sql/cik/create_cik_table.sql +++ b/src/server/sql/cik/create_cik_table.sql @@ -4,9 +4,9 @@ -- create cik table CREATE TABLE IF NOT EXISTS cik ( - row_index INTEGER, - column_index INTEGER, + source_id INTEGER REFERENCES units(id), + destination_id INTEGER REFERENCES units(id), slope FLOAT, intercept FLOAT, - PRIMARY KEY (row_index, column_index) + PRIMARY KEY (source_id, destination_id) ); diff --git a/src/server/sql/cik/get_cik.sql b/src/server/sql/cik/get_cik.sql new file mode 100644 index 000000000..c1339c54c --- /dev/null +++ b/src/server/sql/cik/get_cik.sql @@ -0,0 +1,10 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +-- Get all ciks through joining cik and units tables. +SELECT source_id AS meter_unit_id, destination_id AS non_meter_unit_id, slope, intercept +FROM cik +; diff --git a/src/server/sql/cik/get_conversion.sql b/src/server/sql/cik/get_conversion.sql index 1bbb34579..44c79aee2 100644 --- a/src/server/sql/cik/get_conversion.sql +++ b/src/server/sql/cik/get_conversion.sql @@ -3,4 +3,4 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -- Get conversion for specific row and column in the cik table (same as Cik array). -SELECT * FROM cik WHERE row_index=${rowIndex} and column_index=${columnIndex}; +SELECT * FROM cik WHERE source_id=${sourceId} and destination_id=${destinationId}; diff --git a/src/server/sql/cik/get_number_columns.sql b/src/server/sql/cik/get_number_columns.sql deleted file mode 100644 index 39e109c0e..000000000 --- a/src/server/sql/cik/get_number_columns.sql +++ /dev/null @@ -1,9 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - --- Returns the maximum index for any column in cik (Cik). --- See units/get_max_non_meter_row_index.sql on why this may not be the --- number of columns desired in pik. --- This is likely legacy code that will not be used in the future. -SELECT MAX(column_index) FROM cik; diff --git a/src/server/sql/cik/get_number_rows.sql b/src/server/sql/cik/get_number_rows.sql deleted file mode 100644 index ddf04e24c..000000000 --- a/src/server/sql/cik/get_number_rows.sql +++ /dev/null @@ -1,9 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - --- Returns the maximum index for any row in cik (Cik). --- See units/get_max_meter_row_index.sql on why this may not be the --- number of rows desired in pik. --- This is likely legacy code that will not be used in the future. -SELECT MAX(row_index) FROM cik; diff --git a/src/server/sql/cik/insert_new_conversion.sql b/src/server/sql/cik/insert_new_conversion.sql index 11a02217b..98ab06078 100644 --- a/src/server/sql/cik/insert_new_conversion.sql +++ b/src/server/sql/cik/insert_new_conversion.sql @@ -3,5 +3,5 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -- Inserts a new conversion into the cik table. -INSERT INTO cik (row_index, column_index, slope, intercept) -VALUES (${rowIndex}, ${columnIndex}, ${slope}, ${intercept}); +INSERT INTO cik (source_id, destination_id, slope, intercept) +VALUES (${sourceId}, ${destinationId}, ${slope}, ${intercept}); diff --git a/src/server/sql/reading/create_function_get_3d_readings.sql b/src/server/sql/reading/create_function_get_3d_readings.sql index e3a06685a..56104ccd8 100644 --- a/src/server/sql/reading/create_function_get_3d_readings.sql +++ b/src/server/sql/reading/create_function_get_3d_readings.sql @@ -43,8 +43,6 @@ AS $$ DECLARE -- Holds the range of dates for returned data that fits the actual data. requested_range TSRANGE; - -- The value associated with the graphing unit - unit_column INTEGER; -- The slope of the conversion from meter to graphing units slope FLOAT; -- The intercept of the conversion from meter to graphing units @@ -64,9 +62,6 @@ DECLARE -- The actual number of hours in a reading to use. reading_length_hours_use INTEGER; BEGIN - -- unit_column holds the column index into the cik table. This is the unit that was requested for graphing. - SELECT unit_index INTO unit_column FROM units WHERE id = graphic_unit_id; - -- Get the smallest reading frequency for all meters requested. SELECT min(reading_frequency) INTO meter_frequency FROM (meters m @@ -96,8 +91,7 @@ BEGIN -- Get the conversion from the current meter's unit to the desired graphing unit. SELECT c.slope, c.intercept into slope, intercept FROM meters m - INNER JOIN units u ON m.unit_id = u.id - INNER JOIN cik c on c.row_index = u.unit_index AND c.column_index = unit_column + INNER JOIN cik c on c.source_id = m.unit_id AND c.destination_id = graphic_unit_id WHERE m.id = current_meter_id ; diff --git a/src/server/sql/reading/create_function_get_compare_readings.sql b/src/server/sql/reading/create_function_get_compare_readings.sql index 98a9b1c8e..cee092b6c 100644 --- a/src/server/sql/reading/create_function_get_compare_readings.sql +++ b/src/server/sql/reading/create_function_get_compare_readings.sql @@ -51,12 +51,9 @@ AS $$ DECLARE prev_start TIMESTAMP; prev_end TIMESTAMP; - unit_column INTEGER; BEGIN prev_start := curr_start - shift; prev_end := curr_end - shift; - -- unit_column holds the column index into the cik table. This is the unit that was requested for graphing. - SELECT unit_index INTO unit_column FROM units WHERE id = graphic_unit_id; RETURN QUERY WITH @@ -65,15 +62,12 @@ BEGIN meters.id AS meter_id, -- Convert the reading based on the conversion found below. SUM(r.reading) * c.slope + c.intercept AS reading - FROM ((((readings r + FROM (((readings r INNER JOIN unnest(meter_ids) meters(id) ON r.meter_id = meters.id) - -- This sequence of joins takes the meter id to its unit and in the final join - -- it then uses the unit_index for this unit. INNER JOIN meters m ON m.id = meters.id) - INNER JOIN units u ON m.unit_id = u.id) - -- This is getting the conversion for the meter (row_index) and unit to graph (column_index). + -- This is getting the conversion for the meter and unit to graph. -- The slope and intercept are used above the transform the reading to the desired unit. - INNER JOIN cik c on c.row_index = u.unit_index AND c.column_index = unit_column) + INNER JOIN cik c on c.source_id = m.unit_id AND c.destination_id = graphic_unit_id) WHERE r.start_timestamp >= curr_start AND r.end_timestamp <= curr_end GROUP BY meters.id, c.slope, c.intercept ), @@ -82,15 +76,12 @@ BEGIN meters.id AS meter_id, -- Convert the reading based on the conversion found below. SUM(r.reading) * c.slope + c.intercept AS reading - FROM ((((readings r + FROM (((readings r INNER JOIN unnest(meter_ids) meters(id) ON r.meter_id = meters.id) - -- This sequence of joins takes the meter id to its unit and in the final join - -- it then uses the unit_index for this unit. INNER JOIN meters m ON m.id = meters.id) - INNER JOIN units u ON m.unit_id = u.id) - -- This is getting the conversion for the meter (row_index) and unit to graph (column_index). + -- This is getting the conversion for the meter and unit to graph. -- The slope and intercept are used above the transform the reading to the desired unit. - INNER JOIN cik c on c.row_index = u.unit_index AND c.column_index = unit_column) + INNER JOIN cik c on c.source_id = m.unit_id AND c.destination_id = graphic_unit_id) WHERE r.start_timestamp >= prev_start AND r.end_timestamp <= prev_end GROUP BY meters.id, c.slope, c.intercept ) diff --git a/src/server/sql/reading/create_reading_views.sql b/src/server/sql/reading/create_reading_views.sql index 4da2800c6..5d6b2a78d 100644 --- a/src/server/sql/reading/create_reading_views.sql +++ b/src/server/sql/reading/create_reading_views.sql @@ -204,8 +204,7 @@ daily_readings_unit tsrange(gen.interval_start, gen.interval_start + '1 day'::INTERVAL, '()') AS time_interval FROM ((readings r - -- This sequence of joins takes the meter id to its unit and in the final join - -- it then uses the unit_index for this unit. + -- This sequence of joins takes the meter id to its unit and a unit. INNER JOIN meters m ON r.meter_id = m.id) INNER JOIN units u ON m.unit_id = u.id) CROSS JOIN LATERAL generate_series( @@ -330,8 +329,7 @@ hourly_readings_unit tsrange(gen.interval_start, gen.interval_start + '1 hour'::INTERVAL, '()') AS time_interval FROM ((readings r - -- This sequence of joins takes the meter id to its unit and in the final join - -- it then uses the unit_index for this unit. + -- This sequence of joins takes the meter id to its unit and a unit. INNER JOIN meters m ON r.meter_id = m.id) INNER JOIN units u ON m.unit_id = u.id) CROSS JOIN LATERAL generate_series( @@ -379,7 +377,6 @@ DECLARE requested_range TSRANGE; requested_interval INTERVAL; requested_interval_seconds INTEGER; - unit_column INTEGER; frequency INTERVAL; frequency_seconds INTEGER; -- Which index of the meter_id array you are currently working on. @@ -389,8 +386,6 @@ DECLARE -- Holds accuracy for current meter. current_point_accuracy reading_line_accuracy; BEGIN - -- unit_column holds the column index into the cik table. This is the unit that was requested for graphing. - SELECT unit_index INTO unit_column FROM units WHERE id = graphic_unit_id; -- For each frequency of points, verify that you will get the minimum graphing points to use for each meter. -- Start with the raw, then hourly and then daily if others will not work. -- Loop over all meters. @@ -468,7 +463,7 @@ DECLARE FROM (((readings r INNER JOIN meters m ON m.id = current_meter_id) INNER JOIN units u ON m.unit_id = u.id) - INNER JOIN cik c on c.row_index = u.unit_index AND c.column_index = unit_column) + INNER JOIN cik c on c.source_id = m.unit_id AND c.destination_id = graphic_unit_id) WHERE lower(requested_range) <= r.start_timestamp AND r.end_timestamp <= upper(requested_range) AND r.meter_id = current_meter_id -- This ensures the data is sorted ORDER BY r.start_timestamp ASC; @@ -487,10 +482,9 @@ DECLARE hourly.max_rate * c.slope + c.intercept AS max_rate, lower(hourly.time_interval) AS start_timestamp, upper(hourly.time_interval) AS end_timestamp - FROM (((hourly_readings_unit hourly + FROM ((hourly_readings_unit hourly INNER JOIN meters m ON m.id = current_meter_id) - INNER JOIN units u ON m.unit_id = u.id) - INNER JOIN cik c on c.row_index = u.unit_index AND c.column_index = unit_column) + INNER JOIN cik c on c.source_id = m.unit_id AND c.destination_id = graphic_unit_id) WHERE requested_range @> time_interval AND hourly.meter_id = current_meter_id -- This ensures the data is sorted ORDER BY start_timestamp ASC; @@ -508,15 +502,13 @@ DECLARE daily.max_rate * c.slope + c.intercept AS max_rate, lower(daily.time_interval) AS start_timestamp, upper(daily.time_interval) AS end_timestamp - FROM (((daily_readings_unit daily + FROM ((daily_readings_unit daily -- Get all the meter_ids in the passed array of meters. - -- This sequence of joins takes the meter id to its unit and in the final join - -- it then uses the unit_index for this unit. + -- This sequence of joins takes the meter id to its unit and a unit. INNER JOIN meters m ON m.id = current_meter_id) - INNER JOIN units u ON m.unit_id = u.id) - -- This is getting the conversion for the meter (row_index) and unit to graph (column_index). + -- This is getting the conversion for the meter and unit to graph. -- The slope and intercept are used above the transform the reading to the desired unit. - INNER JOIN cik c on c.row_index = u.unit_index AND c.column_index = unit_column) + INNER JOIN cik c on c.source_id = m.unit_id AND c.destination_id = graphic_unit_id) WHERE requested_range @> time_interval AND daily.meter_id = current_meter_id -- This ensures the data is sorted ORDER BY start_timestamp ASC; @@ -652,7 +644,6 @@ DECLARE real_tsrange TSRANGE; real_start_stamp TIMESTAMP; real_end_stamp TIMESTAMP; - unit_column INTEGER; num_bars INTEGER; BEGIN -- This is how wide (time interval) for each bar. @@ -686,9 +677,6 @@ BEGIN -- end timestamp by that amount so it stops at the desired end timestamp. real_end_stamp := real_end_stamp - bar_width; - -- unit_column holds the column index into the cik table. This is the unit that was requested for graphing. - SELECT unit_index INTO unit_column FROM units WHERE id = graphic_unit_id; - RETURN QUERY SELECT dr.meter_id AS meter_id, -- dr.reading_rate is the weighted average reading rate per hour over the day. @@ -703,13 +691,13 @@ BEGIN -- Get all the meter_ids in the passed array of meters. INNER JOIN unnest(meter_ids) meters(id) ON dr.meter_id = meters.id) -- This sequence of joins takes the meter id to its unit and in the final join - -- it then uses the unit_index for this unit. + -- it then get the desired conversion. INNER JOIN meters m ON m.id = meters.id) -- Don't return bar data if raw since cannot sum. INNER JOIN units u ON m.unit_id = u.id AND u.unit_represent != 'raw'::unit_represent_type) - -- This is getting the conversion for the meter (row_index) and unit to graph (column_index). + -- This is getting the conversion for the meter (source_id) and unit to graph (destination_id). -- The slope and intercept are used above the transform the reading to the desired unit. - INNER JOIN cik c on c.row_index = u.unit_index AND c.column_index = unit_column) + INNER JOIN cik c on c.source_id = m.unit_id AND c.destination_id = graphic_unit_id) GROUP BY dr.meter_id, bars.interval_start, c.slope, c.intercept; END; $$ LANGUAGE 'plpgsql'; diff --git a/src/server/sql/unit/create_units_table.sql b/src/server/sql/unit/create_units_table.sql index 33da40c0f..075a35fc1 100644 --- a/src/server/sql/unit/create_units_table.sql +++ b/src/server/sql/unit/create_units_table.sql @@ -9,13 +9,8 @@ CREATE TABLE IF NOT EXISTS units ( unit_represent unit_represent_type NOT NULL, sec_in_rate INTEGER DEFAULT 3600 CHECK (sec_in_rate > 0), type_of_unit unit_type NOT NULL, - unit_index INTEGER, suffix VARCHAR(50) DEFAULT '', displayable displayable_type NOT NULL, preferred_display BOOLEAN NOT NULL, note TEXT - -- We previously had the following unique constraint. It was difficult to make sure it - -- was met during changes to units so it was removed. See the design document for more - -- details. - -- UNIQUE (type_of_unit, unit_index) ); diff --git a/src/server/sql/unit/get_by_unit_index_meter.sql b/src/server/sql/unit/get_by_unit_index_meter.sql deleted file mode 100644 index 924514802..000000000 --- a/src/server/sql/unit/get_by_unit_index_meter.sql +++ /dev/null @@ -1,6 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -SELECT id FROM units -WHERE type_of_unit = 'meter'::unit_type AND unit_index = ${unitIndex}; \ No newline at end of file diff --git a/src/server/sql/unit/get_max_meter_row_index.sql b/src/server/sql/unit/get_max_meter_row_index.sql deleted file mode 100644 index 129217cdf..000000000 --- a/src/server/sql/unit/get_max_meter_row_index.sql +++ /dev/null @@ -1,10 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - --- Returns the maximum row index for any meter. --- Since rows start at 0 and increase by 1 each time this is the --- number of rows - 1 desired in the pik table. --- This can differ from the number of rows in cik if there is a unit --- that has no conversion that is a higher index than one with a conversion. -SELECT MAX(unit_index) FROM units WHERE type_of_unit = 'meter'::unit_type; diff --git a/src/server/sql/unit/get_max_non_meter_row_index.sql b/src/server/sql/unit/get_max_non_meter_row_index.sql deleted file mode 100644 index 2def4ce31..000000000 --- a/src/server/sql/unit/get_max_non_meter_row_index.sql +++ /dev/null @@ -1,10 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - --- Returns the maximum column index for any non-meter. --- Since columns start at 0 and increase by 1 each time this is the --- number of columns - 1 desired in the pik table. --- This can differ from the number of columns in cik if there is a unit --- that has no conversion that is a higher index than one with a conversion. -SELECT MAX(unit_index) FROM units WHERE type_of_unit <> 'meter'::unit_type; diff --git a/src/server/sql/unit/insert_new_unit.sql b/src/server/sql/unit/insert_new_unit.sql index 80bbcbedb..a4805ed5e 100644 --- a/src/server/sql/unit/insert_new_unit.sql +++ b/src/server/sql/unit/insert_new_unit.sql @@ -2,6 +2,6 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -INSERT INTO units(name, identifier, unit_represent, sec_in_rate, type_of_unit, unit_index, suffix, displayable, preferred_display, note) -VALUES (${name}, ${identifier}, ${unitRepresent}, ${secInRate}, ${typeOfUnit}, ${unitIndex}, ${suffix}, ${displayable}, ${preferredDisplay}, ${note}) +INSERT INTO units(name, identifier, unit_represent, sec_in_rate, type_of_unit, suffix, displayable, preferred_display, note) +VALUES (${name}, ${identifier}, ${unitRepresent}, ${secInRate}, ${typeOfUnit}, ${suffix}, ${displayable}, ${preferredDisplay}, ${note}) RETURNING id; diff --git a/src/server/sql/unit/update_unit.sql b/src/server/sql/unit/update_unit.sql index 328eef1eb..af3594819 100644 --- a/src/server/sql/unit/update_unit.sql +++ b/src/server/sql/unit/update_unit.sql @@ -8,7 +8,6 @@ UPDATE units unit_represent = ${unitRepresent}, sec_in_rate = ${secInRate}, type_of_unit = ${typeOfUnit}, - unit_index = ${unitIndex}, suffix = ${suffix}, displayable = ${displayable}, preferred_display = ${preferredDisplay}, diff --git a/src/server/test/db/conversionTests.js b/src/server/test/db/conversionTests.js index bd0c4da6b..62cd23edf 100644 --- a/src/server/test/db/conversionTests.js +++ b/src/server/test/db/conversionTests.js @@ -24,9 +24,9 @@ mocha.describe('Conversions', () => { mocha.beforeEach(async () => { conn = testDB.getConnection(); const unitA = new Unit(undefined, 'Unit A', 'Unit A', Unit.unitRepresentType.QUANTITY, 1000, - Unit.unitType.UNIT, 1, 'Suffix A', Unit.displayableType.ADMIN, true, 'Note A'); + Unit.unitType.UNIT, 'Suffix A', Unit.displayableType.ADMIN, true, 'Note A'); const unitB = new Unit(undefined, 'Unit B', 'Unit B', Unit.unitRepresentType.QUANTITY, 2000, - Unit.unitType.METER, 1, 'Suffix B', Unit.displayableType.ALL, true, 'Note B'); + Unit.unitType.METER, 'Suffix B', Unit.displayableType.ALL, true, 'Note B'); await unitA.insert(conn); await unitB.insert(conn); }); diff --git a/src/server/test/db/groupTests.js b/src/server/test/db/groupTests.js index b11a55098..e1875b17e 100644 --- a/src/server/test/db/groupTests.js +++ b/src/server/test/db/groupTests.js @@ -13,11 +13,11 @@ const gps = new Point(90, 45); async function setupGroupsAndMeters(conn) { const unitA = new Unit(undefined, 'Unit A', 'Unit A Id', Unit.unitRepresentType.QUANTITY, 1000, - Unit.unitType.UNIT, 1, 'Unit A Suffix', Unit.displayableType.ALL, true, 'Unit A Note'); + Unit.unitType.UNIT, 'Unit A Suffix', Unit.displayableType.ALL, true, 'Unit A Note'); const unitB = new Unit(undefined, 'Unit B', 'Unit B Id', Unit.unitRepresentType.QUANTITY, 2000, - Unit.unitType.UNIT, 2, 'Unit B Suffix', Unit.displayableType.ALL, true, 'Unit B Note'); + Unit.unitType.UNIT, 'Unit B Suffix', Unit.displayableType.ALL, true, 'Unit B Note'); const unitC = new Unit(undefined, 'Unit C', 'Unit C Id', Unit.unitRepresentType.QUANTITY, 3000, - Unit.unitType.UNIT, 3, 'Unit C Suffix', Unit.displayableType.ALL, true, 'Unit C Note'); + Unit.unitType.UNIT, 'Unit C Suffix', Unit.displayableType.ALL, true, 'Unit C Note'); await Promise.all([unitA, unitB, unitC].map(unit => unit.insert(conn))); const unitAId = (await Unit.getByName('Unit A', conn)).id; const unitBId = (await Unit.getByName('Unit B', conn)).id; @@ -74,7 +74,7 @@ mocha.describe('Groups', () => { groupPreInsert.name = 'New name'; const unit = new Unit(undefined, 'Unit', 'Unit Id', Unit.unitRepresentType.QUANTITY, 1000, - Unit.unitType.UNIT, 1, 'Unit Suffix', Unit.displayableType.ALL, true, 'Unit Note'); + Unit.unitType.UNIT, 'Unit Suffix', Unit.displayableType.ALL, true, 'Unit Note'); await unit.insert(conn); const unitId = (await Unit.getByName('Unit', conn)).id; groupPreInsert.defaultGraphicUnit = unitId; diff --git a/src/server/test/db/meterTests.js b/src/server/test/db/meterTests.js index ef30c9783..e57aff6a0 100644 --- a/src/server/test/db/meterTests.js +++ b/src/server/test/db/meterTests.js @@ -62,11 +62,11 @@ mocha.describe('Meters', () => { let unitA, unitB; mocha.beforeEach(async () => { unitA = new Unit(undefined, 'Unit A', 'Unit A Id', Unit.unitRepresentType.QUANTITY, 1000, - Unit.unitType.UNIT, 1, 'Unit A Suffix', Unit.displayableType.ALL, true, 'Unit A Note'); + Unit.unitType.UNIT, 'Unit A Suffix', Unit.displayableType.ALL, true, 'Unit A Note'); unitB = new Unit(undefined, 'Unit B', 'Unit B Id', Unit.unitRepresentType.QUANTITY, 2000, - Unit.unitType.UNIT, 2, 'Unit B Suffix', Unit.displayableType.ALL, true, 'Unit B Note'); + Unit.unitType.UNIT, 'Unit B Suffix', Unit.displayableType.ALL, true, 'Unit B Note'); const unitC = new Unit(undefined, 'Unit C', 'Unit C Id', Unit.unitRepresentType.QUANTITY, 3000, - Unit.unitType.UNIT, 3, 'Unit C Suffix', Unit.displayableType.ALL, true, 'Unit C Note'); + Unit.unitType.UNIT, 'Unit C Suffix', Unit.displayableType.ALL, true, 'Unit C Note'); await Promise.all([unitA, unitB, unitC].map(unit => unit.insert(conn))); }); @@ -157,19 +157,6 @@ mocha.describe('Meters', () => { expectMetersToBeEquivalent(visibleMeter, visibleMeters[0]); }); - mocha.it('can get unit index', async () => { - const conn = testDB.getConnection(); - const visibleMeter = new Meter(undefined, 'VisibleMeter', null, true, true, Meter.type.MAMAC, null, gps, - 'Identified 1', 'notes 1', 35.0, true, true, '01:01:25', '00:00:00', 5, 0, 1, 'increasing', false, - 1.5, '0001-01-01 23:59:59', '2020-07-02 01:00:10', '2020-03-05 02:12:00', unitA.id, unitA.id, - Unit.areaUnitType.METERS, undefined); - await visibleMeter.insert(conn); - - const actualUnitIndex = await Meter.getUnitIndex(1, conn); - const expectedUnitIndex = unitA.unitIndex; - expect(actualUnitIndex).to.be.equal(expectedUnitIndex); - }); - mocha.it('can get all meter where unitId is not null', async () => { const meterA = new Meter(undefined, 'MeterA', null, true, true, Meter.type.MAMAC, null, gps, 'MeterA', 'notes 1', 35.0, true, true, '01:01:25', '00:00:00', 5, 0, 1, 'increasing', false, diff --git a/src/server/test/db/unitTests.js b/src/server/test/db/unitTests.js index 232ede684..d7d6476ea 100644 --- a/src/server/test/db/unitTests.js +++ b/src/server/test/db/unitTests.js @@ -10,7 +10,7 @@ mocha.describe('Units', () => { mocha.it('can be saved and retrieved', async () => { const conn = testDB.getConnection(); const unitTypePreInsert = new Unit(undefined, 'Unit', 'Index', Unit.unitRepresentType.QUANTITY, - 1000, Unit.unitType.UNIT, 5, 'Suffix', Unit.displayableType.ALL, true, 'Note'); + 1000, Unit.unitType.UNIT, 'Suffix', Unit.displayableType.ALL, true, 'Note'); await unitTypePreInsert.insert(conn); // Gets unit by id. const unitTypePostInsertById = await Unit.getById(unitTypePreInsert.id, conn); @@ -18,25 +18,11 @@ mocha.describe('Units', () => { // Gets unit by name. const unitTypePostInsertByName = await Unit.getByName('Unit', conn); expectUnitToBeEquivalent(unitTypePreInsert, unitTypePostInsertByName); - // Gets unit by index. - const idUnitTypePostInsertByIdentifier = await Unit.getByUnitIndexUnit(unitTypePreInsert.unitIndex, conn); - expect(idUnitTypePostInsertByIdentifier).to.be.equal(unitTypePostInsertById.id); }); - - mocha.it('meter type can be retrieved by unitIndex', async () => { - const conn = testDB.getConnection(); - const meterTypePreInsert = new Unit(undefined, 'Meter', 'Meter Id', Unit.unitRepresentType.QUANTITY, - 1000, Unit.unitType.METER, 5, 'Suffix', Unit.displayableType.ALL, true, 'Note'); - await meterTypePreInsert.insert(conn); - const meterTypePostInsertId = (await Unit.getByName('Meter', conn)).id; - const idMeterTypePostInsertByIdentifier = await Unit.getByUnitIndexMeter(meterTypePreInsert.unitIndex, conn); - expect(idMeterTypePostInsertByIdentifier).to.be.equal(meterTypePostInsertId); - }); - mocha.it('can be saved, edited, and retrieved', async () => { const conn = testDB.getConnection(); const unitPreInsert = new Unit(undefined, 'Unit', 'Unit Id', Unit.unitRepresentType.QUANTITY, - 1000, Unit.unitType.UNIT, 5, 'Suffix', Unit.displayableType.ALL, true, 'Note'); + 1000, Unit.unitType.UNIT, 'Suffix', Unit.displayableType.ALL, true, 'Note'); await unitPreInsert.insert(conn); const unitPostInsert = await Unit.getById(1, conn); // Edits the unit. @@ -54,17 +40,17 @@ mocha.describe('Units', () => { mocha.beforeEach(async () => { const conn = testDB.getConnection(); const unitTypeMeterAll = new Unit(undefined, 'Meter All', 'Meter All Id', Unit.unitRepresentType.QUANTITY, 2000, - Unit.unitType.METER, 1, '', Unit.displayableType.ALL, true, 'Meter All Note'); + Unit.unitType.METER, '', Unit.displayableType.ALL, true, 'Meter All Note'); const unitTypeMeterAdmin = new Unit(undefined, 'Meter Admin', 'Meter Admin Id', Unit.unitRepresentType.QUANTITY, 3000, - Unit.unitType.METER, 2, 'Meter Admin Suffix', Unit.displayableType.ADMIN, true, 'Meter Admin Note'); + Unit.unitType.METER, 'Meter Admin Suffix', Unit.displayableType.ADMIN, true, 'Meter Admin Note'); const unitTypeUnitAll = new Unit(undefined, 'Unit All', 'Unit All Id', Unit.unitRepresentType.QUANTITY, 4000, - Unit.unitType.UNIT, 3, '', Unit.displayableType.ALL, true, 'Unit All Note'); + Unit.unitType.UNIT, '', Unit.displayableType.ALL, true, 'Unit All Note'); const unitTypeUnitAdmin = new Unit(undefined, 'Unit Admin', 'Unit Admin Id', Unit.unitRepresentType.QUANTITY, 5000, - Unit.unitType.UNIT, 4, 'Unit Admin Suffix', Unit.displayableType.ADMIN, true, 'Unit Admin Note'); + Unit.unitType.UNIT, 'Unit Admin Suffix', Unit.displayableType.ADMIN, true, 'Unit Admin Note'); const unitTypeSuffixAll = new Unit(undefined, 'Suffix All', 'Suffix All Id', Unit.unitRepresentType.QUANTITY, 6000, - Unit.unitType.SUFFIX, 5, '', Unit.displayableType.ALL, true, 'Suffix All Note'); + Unit.unitType.SUFFIX, '', Unit.displayableType.ALL, true, 'Suffix All Note'); const unitTypeSuffixNone = new Unit(undefined, 'Suffix None', 'Suffix None Id', Unit.unitRepresentType.QUANTITY, 7000, - Unit.unitType.SUFFIX, 6, 'Suffix None Suffix', Unit.displayableType.NONE, true, 'Suffix None Note'); + Unit.unitType.SUFFIX, 'Suffix None Suffix', Unit.displayableType.NONE, true, 'Suffix None Note'); const units = [unitTypeMeterAll, unitTypeMeterAdmin, unitTypeUnitAll, unitTypeUnitAdmin, unitTypeSuffixAll, unitTypeSuffixNone]; await Promise.all(units.map(unit => unit.insert(conn))); }); diff --git a/src/server/test/web/groups.js b/src/server/test/web/groups.js index 12bcfd276..d79bba708 100644 --- a/src/server/test/web/groups.js +++ b/src/server/test/web/groups.js @@ -32,7 +32,7 @@ mocha.describe('groups API', () => { * - - - meter C */ await new Unit(undefined, 'Unit', 'Unit', Unit.unitRepresentType.QUANTITY, 1000, Unit.unitType.UNIT, - 1, 'Unit Suffix', Unit.displayableType.ALL, true, 'Unit Note').insert(conn); + 'Unit Suffix', Unit.displayableType.ALL, true, 'Unit Note').insert(conn); const unitId = (await Unit.getByName('Unit', conn)).id; groupA = new Group(undefined, 'A', true, gpsPoint, 'notes A', 33.5, unitId, Unit.areaUnitType.METERS); groupB = new Group(undefined, 'B', false, gpsPoint, 'notes B', 43.5, unitId, Unit.areaUnitType.METERS); diff --git a/src/server/test/web/meters.js b/src/server/test/web/meters.js index 055cba7eb..e35ed355d 100644 --- a/src/server/test/web/meters.js +++ b/src/server/test/web/meters.js @@ -99,7 +99,7 @@ mocha.describe('meters API', () => { mocha.beforeEach(async () => { conn = testDB.getConnection(); const unit = new Unit(undefined, 'Unit', 'Unit', Unit.unitRepresentType.QUANTITY, 1000, Unit.unitType.UNIT, - 1, 'Unit Suffix', Unit.displayableType.ALL, true, 'Unit Note'); + 'Unit Suffix', Unit.displayableType.ALL, true, 'Unit Note'); await unit.insert(conn); unitId = unit.id; }); diff --git a/src/server/test/web/unitsTest.js b/src/server/test/web/unitsTest.js index 8bd54605d..486b7758a 100644 --- a/src/server/test/web/unitsTest.js +++ b/src/server/test/web/unitsTest.js @@ -19,7 +19,7 @@ mocha.describe("Units routes", () => { mocha.it('returns one visible unit', async () => { const conn = testDB.getConnection(); - const expected = new Unit(undefined, 'kwh', 'kWh', Unit.unitRepresentType.QUANTITY, undefined, Unit.unitType.UNIT, null, '', Unit.displayableType.ALL, true, "standard unit"); + const expected = new Unit(undefined, 'kwh', 'kWh', Unit.unitRepresentType.QUANTITY, undefined, Unit.unitType.UNIT, '', Unit.displayableType.ALL, true, "standard unit"); await expected.insert(conn); const res = await chai.request(app).get('/api/units'); expect(res).to.have.status(200); @@ -48,7 +48,7 @@ mocha.describe("Units routes", () => { for (let i = 0; i < units.length; ++i) { const unitData = units[i]; const aUnit = new Unit(undefined, unitData[0], unitData[1], unitData[2], undefined, - unitData[3], null, unitData[4], unitData[5], unitData[6], 'test unit' + i); + unitData[3], unitData[4], unitData[5], unitData[6], 'test unit' + i); expectedUnits.push(aUnit); await aUnit.insert(conn); } diff --git a/src/server/util/compareUnits.js b/src/server/util/compareUnits.js index 9e1f20000..4dc78d3aa 100644 --- a/src/server/util/compareUnits.js +++ b/src/server/util/compareUnits.js @@ -17,7 +17,6 @@ function expectUnitToBeEquivalent(expected, actual) { expect(actual).to.have.property('unitRepresent', expected.unitRepresent); expect(actual).to.have.property('secInRate', expected.secInRate); expect(actual).to.have.property('typeOfUnit', expected.typeOfUnit); - expect(actual).to.have.property('unitIndex', expected.unitIndex); expect(actual).to.have.property('suffix', expected.suffix); expect(actual).to.have.property('displayable', expected.displayable); expect(actual).to.have.property('preferredDisplay', expected.preferredDisplay); diff --git a/src/server/util/insertData.js b/src/server/util/insertData.js index 16c899ff0..932b0d814 100644 --- a/src/server/util/insertData.js +++ b/src/server/util/insertData.js @@ -36,7 +36,7 @@ async function insertUnits(unitsToInsert, update = false, conn) { if (dbUnit === null) { // The unit does not exist so add it. await new Unit(undefined, unitData.name, unitData.identifier, unitData.unitRepresent, unitData.secInRate, - unitData.typeOfUnit, null, unitData.suffix, unitData.displayable, unitData.preferredDisplay, unitData.note).insert(conn); + unitData.typeOfUnit, unitData.suffix, unitData.displayable, unitData.preferredDisplay, unitData.note).insert(conn); } else if (update) { // Asked to update so will. Does not bother to check if no changes. dbUnit.name = unitData.name;