Skip to content

Commit

Permalink
Merge pull request #3522 from LiteFarmOrg/LF-4523/Animals_internal_id…
Browse files Browse the repository at this point in the history
…entifier_changes

LF-4523: Animals internal identifier changes after data updates
  • Loading branch information
antsgar authored Nov 8, 2024
2 parents 5f7bd63 + 360433d commit cf00826
Show file tree
Hide file tree
Showing 3 changed files with 195 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright 2024 LiteFarm.org
* This file is part of LiteFarm.
*
* LiteFarm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LiteFarm is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details, see <https://www.gnu.org/licenses/>.
*/

import { fileURLToPath } from 'url';
import path, { dirname } from 'path';
import fs from 'fs';

/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
export const up = async function (knex) {
try {
await knex.schema.dropView('animal_union_batch_id_view');

// Recreate animal_union_batch_id_view VIEW
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const sqlFilePath = path.join(
__dirname,
'../sql/20241108052304_animal_union_batch_id_view.sql',
);
const sqlQuery = fs.readFileSync(sqlFilePath).toString();
await knex.raw(sqlQuery);
} catch (error) {
console.error('Error in migration up:', error);
throw error; // Rethrow the error to ensure the migration fails
}
};

/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
export const down = async (knex) => {
try {
await knex.schema.dropView('animal_union_batch_id_view');

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const sqlFilePath = path.join(
__dirname,
'../sql/20240207214919_animal_union_batch_id_view.sql',
);
const sqlQuery = fs.readFileSync(sqlFilePath).toString();
await knex.raw(sqlQuery);
} catch (error) {
console.error('Error in migration down:', error);
throw error; // Rethrow the error to ensure the migration fails
}
};
40 changes: 40 additions & 0 deletions packages/api/db/sql/20241108052304_animal_union_batch_id_view.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright 2024 LiteFarm.org
* This file is part of LiteFarm.
*
* LiteFarm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LiteFarm is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details, see <https://www.gnu.org/licenses/>.
*/

CREATE VIEW animal_union_batch_id_view AS
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY farm_id ORDER BY created_at, id, batch)::INTEGER AS internal_identifier
FROM (
SELECT
id,
farm_id,
FALSE AS batch,
created_at
FROM
animal a

UNION ALL

SELECT
id,
farm_id,
TRUE AS batch,
created_at
FROM
animal_batch ab
) animal_union_batch_id_view
ORDER BY
created_at, id, batch;
92 changes: 92 additions & 0 deletions packages/api/tests/animal_union_batch.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,58 @@
* GNU General Public License for more details, see <https://www.gnu.org/licenses/>.
*/

import chai from 'chai';
import chaiHttp from 'chai-http';

chai.use(chaiHttp);
import server from '../src/server.js';
import knex from '../src/util/knex.js';

jest.mock('jsdom');
jest.mock('../src/middleware/acl/checkJwt.js', () =>
jest.fn((req, res, next) => {
req.auth = {};
req.auth.user_id = req.get('user_id');
next();
}),
);
import { tableCleanup } from './testEnvironment.js';
import mocks from './mock.factories.js';
import animalUnionBatchIdViewModel from '../src/models/animalUnionBatchIdViewModel.js';
import { makeAnimalOrBatchForFarm } from './utils/animalUtils.js';

const getAnimals = async (user_id, farm_id) => {
return chai.request(server).get('/animals').set('user_id', user_id).set('farm_id', farm_id);
};

const getBatches = async (user_id, farm_id) => {
return chai
.request(server)
.get('/animal_batches')
.set('user_id', user_id)
.set('farm_id', farm_id);
};

const patchAnimals = async (user_id, farm_id, data) => {
return chai
.request(server)
.patch('/animals')
.set('Content-Type', 'application/json')
.set('user_id', user_id)
.set('farm_id', farm_id)
.send(data);
};

const patchBatches = async (user_id, farm_id, data) => {
return chai
.request(server)
.patch('/animal_batches')
.set('Content-Type', 'application/json')
.set('user_id', user_id)
.set('farm_id', farm_id)
.send(data);
};

describe('Animal Union Batch Tests', () => {
afterEach(async (done) => {
await tableCleanup(knex);
Expand Down Expand Up @@ -72,5 +117,52 @@ describe('Animal Union Batch Tests', () => {
});
}
});

test('Internal identifiers should not change after data is updated', async () => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({ roleId: 1 });

const animals = await Promise.all(
Array(4)
.fill()
.map(() => mocks.animalFactory({ promisedFarm: [{ farm_id }] })),
);
const batches = await Promise.all(
Array(4)
.fill()
.map(() => mocks.animal_batchFactory({ promisedFarm: [{ farm_id }] })),
);

// Set created_at to a fixed value to ensure the order is determined by other columns (batch, id)
await knex('animal').update({ created_at: '2024-11-08 00:00:00.000-00' });
await knex('animal_batch').update({ created_at: '2024-11-08 00:00:00.000-00' });

const animalsBeforeRes = await getAnimals(user_id, farm_id);
const batchesBeforeRes = await getBatches(user_id, farm_id);

for (let i = 0; i < 10; i++) {
await patchAnimals(
user_id,
farm_id,
animals.map(([animal]) => ({ id: animal.id, notes: '' })),
);
await patchBatches(
user_id,
farm_id,
batches.map(([batch]) => ({ id: batch.id, notes: '' })),
);

const animalsAfterRes = await getAnimals(user_id, farm_id);
animalsBeforeRes.body.forEach((before) => {
const after = animalsAfterRes.body.find(({ id }) => before.id === id);
expect(before.internal_identifier).toBe(after.internal_identifier);
});

const batchesAfterRes = await getBatches(user_id, farm_id);
batchesBeforeRes.body.forEach((before) => {
const after = batchesAfterRes.body.find(({ id }) => before.id === id);
expect(before.internal_identifier).toBe(after.internal_identifier);
});
}
});
});
});

0 comments on commit cf00826

Please sign in to comment.