Peace 1 month ago
parent 51b37886e0
commit 282a166284
  1. 2
      backend/dist/tsconfig.build.tsbuildinfo
  2. 0
      backend/src/common/entities/error-log.entity.ts
  3. 13
      backend/src/scripts/seed-sensors.ts
  4. 16
      backend/src/sensors/entities/sensor-data.entity.ts
  5. 5
      backend/src/sensors/entities/sensor-group.entity.ts
  6. 5
      backend/src/sensors/entities/sensor.entity.ts
  7. 4
      backend/src/sensors/sensors.controller.ts
  8. 20
      backend/src/sensors/sensors.service.ts
  9. 1
      backend/src/users/entities/user.entity.ts
  10. 4
      backend/src/utils/query_utils.ts

File diff suppressed because one or more lines are too long

@ -14,10 +14,10 @@ async function run() {
await queryRunner.startTransaction();
try {
const userRepo = AppDataSource.getRepository(User);
const groupRepo = AppDataSource.getRepository(SensorGroup);
const sensorRepo = AppDataSource.getRepository(Sensor);
const dataRepo = AppDataSource.getRepository(SensorData);
const userRepo = queryRunner.manager.getRepository(User);
const groupRepo = queryRunner.manager.getRepository(SensorGroup);
const sensorRepo = queryRunner.manager.getRepository(Sensor);
const dataRepo = queryRunner.manager.getRepository(SensorData);
for (let i = 0; i < 2; i++) {
const name = `seed_user_${faker.finance.amount({ min: 0, max: 100, dec: 0 })}`;
@ -37,8 +37,9 @@ async function run() {
}
for (let i = 0; i < 2; i++) {
const groupOwner = `${faker.person.fullName()}`;
const group = groupRepo.create({
name: `SensorGroup_${i + 1}`,
name: `SensorGroup_${groupOwner}`,
users,
});
await groupRepo.save(group);
@ -46,7 +47,7 @@ async function run() {
for (let j = 0; j < 2; j++) {
const sensor = sensorRepo.create({
name: `sensor_${i + 1}_${j + 1}`,
name: `sensor_${groupOwner}_${j + 1}`,
group,
});
await sensorRepo.save(sensor);

@ -1,11 +1,4 @@
import {
Column,
CreateDateColumn,
Entity,
Index,
ManyToOne,
PrimaryGeneratedColumn,
} from 'typeorm';
import { Column, Entity, Index, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
import { Sensor } from './sensor.entity';
@Entity()
@ -17,8 +10,11 @@ export class SensorData {
@Column('float')
value: number;
@Index()
@CreateDateColumn({ type: 'timestamp' })
@Column({
type: 'timestamp',
precision: 3,
default: () => 'CURRENT_TIMESTAMP(3)',
})
recordedAt: Date;
@ManyToOne(() => Sensor, (sensor) => sensor.data, { onDelete: 'CASCADE' }) // FK Onwer

@ -11,10 +11,9 @@ export class SensorGroup extends TimestampedEntity {
@Column({ unique: true })
name: string;
@Column()
description: string;
@Column({ nullable: true })
description?: string;
@Index()
@ManyToMany(() => User, (user) => user.sensorGroups)
users: User[];

@ -11,10 +11,9 @@ export class Sensor extends TimestampedEntity {
@Column({ unique: true })
name: string;
@Column()
unit: string;
@Column({ nullable: true })
unit?: string;
@Index()
@ManyToOne(() => SensorGroup, (group) => group.sensors, { onDelete: 'CASCADE' }) // FK Onwer
group: SensorGroup;

@ -8,6 +8,7 @@ import {
ParseIntPipe,
Param,
Query,
HttpCode,
} from '@nestjs/common';
import { SensorsService } from './sensors.service';
import { ApiBearerAuth, ApiOkResponse, ApiOperation, ApiQuery, ApiTags } from '@nestjs/swagger';
@ -30,6 +31,7 @@ export class SensorsController {
//#region Group
@Post('sensor-groups')
@HttpCode(200)
@ApiOperation({ summary: '센서 그룹 생성' })
@ApiOkResponse({ description: '성공', type: SensorGroupResponseDto })
async createGroup(
@ -49,6 +51,7 @@ export class SensorsController {
//#region Sensor
@Post('sensors')
@HttpCode(200)
@ApiOperation({ summary: '센서 생성' })
@ApiOkResponse({ description: '성공', type: SensorResponseDto })
async createSensor(
@ -71,6 +74,7 @@ export class SensorsController {
//#region Data
@Post('sensors/:sensorId/data')
@HttpCode(200)
@ApiOperation({ summary: '센서 데이터 생성' })
@ApiOkResponse({ description: '성공', type: SensorDataResponseDto })
async createData(

@ -16,6 +16,7 @@ import { CreateSensorDto } from './dto/create-sensor.dto';
import { SensorResponseDto } from './dto/sensor-response.dto';
import { SensorDataResponseDto } from './dto/sensor-data-response.dto';
import { CreateSensorDataDto } from './dto/create-sensor-data.dto';
import { normalizeLimit } from 'src/utils/query_utils';
@Injectable()
export class SensorsService {
@ -144,21 +145,18 @@ export class SensorsService {
opts: { from?: Date; to?: Date; limit?: number },
): Promise<SensorDataResponseDto[]> {
await this.assertMemeberOfSensor(currentUserId, sensorId);
const take = Math.min(Math.max(opts.limit ?? 50, 1), 500); // 1 ~ 500개
const take = normalizeLimit(opts.limit);
const from = opts.from ?? new Date(0);
const to = opts.to ?? new Date();
const data = this.dataRepo
.createQueryBuilder('d')
.select(['d.id', 'd.value', 'd.recordedAt'])
.where('data.sensorId = :sensorId', { sensorId });
.select(['d.id AS id', 'd.value AS value', 'd.recordedAt AS recordedAt'])
.where('d.sensorId = :sensorId', { sensorId })
.andWhere('d.recordedAt BETWEEN :from AND :to', { from, to })
.orderBy('d.recordedAt', 'DESC')
.take(take);
if (opts.from || opts.to) {
data.andWhere('data.recordedAt BETWEEN :from AND :to', {
from: opts.from ?? new Date(0),
to: opts.to ?? new Date(),
});
}
data.orderBy('data.recordedAt', 'DESC').take(take);
const list = await data.getRawMany<SensorData>();
return list.map((d) => ({ id: d.id, value: d.value, recordedAt: d.recordedAt }));

@ -36,6 +36,5 @@ export class User extends TimestampedEntity {
@ManyToMany(() => SensorGroup, (group) => group.users)
@JoinTable() // Join table Owner
@Index()
sensorGroups: SensorGroup[];
}

@ -0,0 +1,4 @@
export function normalizeLimit(limit?: number, min = 1, max = 500, def = 50) {
const value = limit ?? def;
return Math.min(Math.max(value, min), max);
}
Loading…
Cancel
Save