|
1 | 1 | 'use strict'; |
2 | 2 |
|
3 | 3 | const crypto = require('crypto'); |
4 | | -const { deviceTable, sensorTable, accessTokenTable } = require('../../schema/schema'); |
| 4 | +const { deviceTable, sensorTable, accessTokenTable, deviceToLocationTable, locationTable } = require('../../schema/schema'); |
5 | 5 | const sensorLayouts = require('../box/sensorLayouts'); |
6 | 6 | const { db } = require('../drizzle'); |
7 | 7 | const ModelError = require('../modelError'); |
8 | | -const { inArray, arrayContains, sql, eq, asc, ilike, getTableColumns } = require('drizzle-orm'); |
| 8 | +const { inArray, arrayContains, sql, eq, asc, ilike } = require('drizzle-orm'); |
9 | 9 | const { insertMeasurement, insertMeasurements } = require('../measurement'); |
10 | 10 | const SketchTemplater = require('@sensebox/sketch-templater'); |
11 | 11 |
|
@@ -94,42 +94,78 @@ const createDevice = async function createDevice (userId, params) { |
94 | 94 | } |
95 | 95 | } |
96 | 96 |
|
97 | | - // TODO: handle in transaction |
98 | | - const [device] = await db |
99 | | - .insert(deviceTable) |
100 | | - .values({ |
101 | | - userId, |
102 | | - name, |
103 | | - exposure, |
104 | | - description, |
105 | | - latitude: location[1], |
106 | | - longitude: location[0], |
107 | | - location: sql`ST_SetSRID(ST_MakePoint(${location[1]}, ${location[0]}), 4326)`, |
108 | | - useAuth, |
109 | | - model, |
110 | | - tags: grouptag |
111 | | - }) |
112 | | - .returning(); |
113 | | - |
114 | | - const [accessToken] = await db.insert(accessTokenTable).values({ |
115 | | - deviceId: device.id, |
116 | | - token: crypto.randomBytes(32).toString('hex') |
117 | | - }) |
118 | | - .returning({ token: accessTokenTable.token }); |
119 | | - |
120 | | - // Iterate over sensors and add device id |
121 | | - sensors = sensors.map((sensor) => ({ |
122 | | - deviceId: device.id, |
123 | | - ...sensor |
124 | | - })); |
125 | | - |
126 | | - const deviceSensors = await db.insert(sensorTable).values(sensors) |
127 | | - .returning(); |
| 97 | + // Handle everything in a transaction to ensure consistency |
| 98 | + const device = await db.transaction(async (tx) => { |
| 99 | + const [device] = await tx |
| 100 | + .insert(deviceTable) |
| 101 | + .values({ |
| 102 | + userId, |
| 103 | + name, |
| 104 | + exposure, |
| 105 | + description, |
| 106 | + useAuth, |
| 107 | + model, |
| 108 | + latitude: location[1], |
| 109 | + longitude: location[0], |
| 110 | + tags: grouptag |
| 111 | + }) |
| 112 | + .returning(); |
| 113 | + |
| 114 | + const [geometry] = await tx |
| 115 | + .insert(locationTable) |
| 116 | + .values({ |
| 117 | + location: sql`ST_SetSRID(ST_MakePoint(${location[1]}, ${location[0]}), 4326)` |
| 118 | + }) |
| 119 | + .onConflictDoNothing() |
| 120 | + .returning({ id: locationTable.id }); |
| 121 | + |
| 122 | + if (geometry) { |
| 123 | + // Create location relation |
| 124 | + await tx |
| 125 | + .insert(deviceToLocationTable) |
| 126 | + .values({ deviceId: device.id, locationId: geometry.id }); |
| 127 | + } else { |
| 128 | + // Get location id |
| 129 | + const geom = await tx.query.locationTable.findFirst({ |
| 130 | + columns: { |
| 131 | + id: true |
| 132 | + }, |
| 133 | + where: sql`ST_Equals(${locationTable.location}, ST_SetSRID(ST_MakePoint(${location[1]}, ${location[0]}), 4326))` |
| 134 | + }); |
| 135 | + |
| 136 | + // Create location relation |
| 137 | + await tx |
| 138 | + .insert(deviceToLocationTable) |
| 139 | + .values({ deviceId: device.id, locationId: geom.id }); |
| 140 | + } |
128 | 141 |
|
129 | | - device['accessToken'] = accessToken.token; |
130 | | - device['sensors'] = deviceSensors; |
| 142 | + const [accessToken] = await tx |
| 143 | + .insert(accessTokenTable) |
| 144 | + .values({ |
| 145 | + deviceId: device.id, |
| 146 | + token: crypto.randomBytes(32).toString('hex') |
| 147 | + }) |
| 148 | + .returning({ token: accessTokenTable.token }); |
| 149 | + |
| 150 | + // Iterate over sensors and add device id |
| 151 | + sensors = sensors.map((sensor) => ({ |
| 152 | + deviceId: device.id, |
| 153 | + ...sensor |
| 154 | + })); |
| 155 | + |
| 156 | + const deviceSensors = await tx |
| 157 | + .insert(sensorTable) |
| 158 | + .values(sensors) |
| 159 | + .returning(); |
| 160 | + |
| 161 | + device['accessToken'] = accessToken.token; |
| 162 | + device['sensors'] = deviceSensors; |
| 163 | + |
| 164 | + return device; |
| 165 | + }); |
131 | 166 |
|
132 | 167 | return device; |
| 168 | + |
133 | 169 | }; |
134 | 170 |
|
135 | 171 | const deleteDevice = async function (filter) { |
|
0 commit comments