|
7 | 7 | LAND_TABLE,
|
8 | 8 | LAND_ROOM_ID,
|
9 | 9 | LAND_AGENT_ID,
|
10 |
| - DEFAULT_MATCH_THRESHOLD |
| 10 | + DEFAULT_MATCH_THRESHOLD, |
| 11 | + OrderByParameter |
11 | 12 | } from "../types";
|
12 | 13 |
|
13 | 14 | const LAND_MEMORY_TYPE = 'land_plot';
|
@@ -52,7 +53,6 @@ export class LandDatabaseAdapter {
|
52 | 53 | async removeAllLandMemories(roomId: UUID): Promise<void> {
|
53 | 54 | await this.dbAdapter.removeAllMemories(roomId, LAND_MEMORY_TYPE, LAND_TABLE);
|
54 | 55 | } */
|
55 |
| - |
56 | 56 | async searchLandByMetadata(params: LandSearchParams): Promise<LandPlotMemory[]> {
|
57 | 57 | let sql = `
|
58 | 58 | SELECT * FROM ${LAND_TABLE}
|
@@ -166,6 +166,165 @@ export class LandDatabaseAdapter {
|
166 | 166 | }
|
167 | 167 | }
|
168 | 168 |
|
| 169 | + async searchLandByMetadataV2(params: LandSearchParams, orderBy?: OrderByParameter): Promise<LandPlotMemory[]> { |
| 170 | + let sql = ` |
| 171 | + SELECT * FROM ${LAND_TABLE} |
| 172 | + WHERE type = $1 |
| 173 | + AND content IS NOT NULL |
| 174 | + `; |
| 175 | + const values: any[] = [LAND_MEMORY_TYPE]; |
| 176 | + let paramCount = 1; |
| 177 | + |
| 178 | + // Add names condition |
| 179 | + if (params.names?.length) { |
| 180 | + paramCount++; |
| 181 | + sql += ` AND content->'metadata'->>'name' = ANY($${paramCount}::text[])`; |
| 182 | + values.push(params.names); |
| 183 | + } |
| 184 | + |
| 185 | + if (params.neighborhoods?.length) { |
| 186 | + paramCount++; |
| 187 | + sql += ` AND content->'metadata'->>'neighborhood' = ANY($${paramCount}::text[])`; |
| 188 | + values.push(params.neighborhoods); |
| 189 | + } |
| 190 | + |
| 191 | + if (params.zoningTypes?.length) { |
| 192 | + paramCount++; |
| 193 | + sql += ` AND content->'metadata'->>'zoning' = ANY($${paramCount}::text[])`; |
| 194 | + values.push(params.zoningTypes); |
| 195 | + } |
| 196 | + |
| 197 | + if (params.plotSizes?.length) { |
| 198 | + paramCount++; |
| 199 | + sql += ` AND content->'metadata'->>'plotSize' = ANY($${paramCount}::text[])`; |
| 200 | + values.push(params.plotSizes); |
| 201 | + } |
| 202 | + |
| 203 | + if (params.buildingTypes?.length) { |
| 204 | + paramCount++; |
| 205 | + sql += ` AND content->'metadata'->>'buildingType' = ANY($${paramCount}::text[])`; |
| 206 | + values.push(params.buildingTypes); |
| 207 | + } |
| 208 | + |
| 209 | + if (params.distances?.ocean) { |
| 210 | + if (params.distances.ocean.maxMeters) { |
| 211 | + paramCount++; |
| 212 | + sql += ` AND (content->'metadata'->'distances'->'ocean'->>'meters')::int <= $${paramCount}`; |
| 213 | + values.push(params.distances.ocean.maxMeters); |
| 214 | + } |
| 215 | + if (params.distances.ocean.category) { |
| 216 | + paramCount++; |
| 217 | + sql += ` AND content->'metadata'->'distances'->'ocean'->>'category' = $${paramCount}`; |
| 218 | + values.push(params.distances.ocean.category); |
| 219 | + } |
| 220 | + } |
| 221 | + |
| 222 | + if (params.distances?.bay) { |
| 223 | + if (params.distances.bay.maxMeters) { |
| 224 | + paramCount++; |
| 225 | + sql += ` AND (content->'metadata'->'distances'->'bay'->>'meters')::int <= $${paramCount}`; |
| 226 | + values.push(params.distances.bay.maxMeters); |
| 227 | + } |
| 228 | + if (params.distances.bay.category) { |
| 229 | + paramCount++; |
| 230 | + sql += ` AND content->'metadata'->'distances'->'bay'->>'category' = $${paramCount}`; |
| 231 | + values.push(params.distances.bay.category); |
| 232 | + } |
| 233 | + } |
| 234 | + |
| 235 | + if (params.building?.floors) { |
| 236 | + if (params.building.floors.min) { |
| 237 | + paramCount++; |
| 238 | + sql += ` AND (content->'metadata'->'building'->'floors'->>'min')::int >= $${paramCount}`; |
| 239 | + values.push(params.building.floors.min); |
| 240 | + } |
| 241 | + if (params.building.floors.max) { |
| 242 | + paramCount++; |
| 243 | + sql += ` AND (content->'metadata'->'building'->'floors'->>'max')::int <= $${paramCount}`; |
| 244 | + values.push(params.building.floors.max); |
| 245 | + } |
| 246 | + } |
| 247 | + |
| 248 | + if (params.building?.height) { |
| 249 | + if (params.building.height.min) { |
| 250 | + paramCount++; |
| 251 | + sql += ` AND (content->'metadata'->'building'->'height'->>'min')::int >= $${paramCount}`; |
| 252 | + values.push(params.building.height.min); |
| 253 | + } |
| 254 | + if (params.building.height.max) { |
| 255 | + paramCount++; |
| 256 | + sql += ` AND (content->'metadata'->'building'->'height'->>'max')::int <= $${paramCount}`; |
| 257 | + values.push(params.building.height.max); |
| 258 | + } |
| 259 | + } |
| 260 | + |
| 261 | + if (params.rarity?.rankRange) { |
| 262 | + if (params.rarity.rankRange.min) { |
| 263 | + paramCount++; |
| 264 | + sql += ` AND (content->'metadata'->>'rank')::int >= $${paramCount}`; |
| 265 | + values.push(params.rarity.rankRange.min); |
| 266 | + } |
| 267 | + if (params.rarity.rankRange.max) { |
| 268 | + paramCount++; |
| 269 | + sql += ` AND (content->'metadata'->>'rank')::int <= $${paramCount}`; |
| 270 | + values.push(params.rarity.rankRange.max); |
| 271 | + } |
| 272 | + } |
| 273 | + |
| 274 | + // Add tokenId search condition |
| 275 | + if (params.tokenId) { |
| 276 | + paramCount++; |
| 277 | + sql += ` AND content->'metadata'->>'tokenId' = $${paramCount}`; |
| 278 | + values.push(params.tokenId); |
| 279 | + } |
| 280 | + |
| 281 | + // Add ORDER BY clause based on orderBy parameter |
| 282 | + if (orderBy) { |
| 283 | + console.log("ORDER BY", orderBy); |
| 284 | + switch (orderBy) { |
| 285 | + case OrderByParameter.Largest: |
| 286 | + sql += ` ORDER BY (content->'metadata'->'plotArea')::float DESC NULLS LAST`; |
| 287 | + break; |
| 288 | + case OrderByParameter.Smallest: |
| 289 | + sql += ` ORDER BY (content->'metadata'->'plotArea')::float ASC NULLS LAST`; |
| 290 | + break; |
| 291 | + case OrderByParameter.Cheapest: |
| 292 | + sql += ` ORDER BY (content->'metadata'->'nftData'->'price')::float ASC NULLS LAST`; |
| 293 | + break; |
| 294 | + case OrderByParameter.MostExpensive: |
| 295 | + sql += ` ORDER BY (content->'metadata'->'nftData'->'price')::float DESC NULLS LAST`; |
| 296 | + break; |
| 297 | + case OrderByParameter.Tallest: |
| 298 | + sql += ` ORDER BY (content->'metadata'->'building'->'height'->>'max')::int DESC NULLS LAST`; |
| 299 | + break; |
| 300 | + case OrderByParameter.Shortest: |
| 301 | + sql += ` ORDER BY (content->'metadata'->'building'->'height'->>'max')::int ASC NULLS LAST`; |
| 302 | + break; |
| 303 | + case OrderByParameter.ClosestToOcean: |
| 304 | + sql += ` ORDER BY (content->'metadata'->'distances'->'ocean'->>'meters')::int ASC`; |
| 305 | + break; |
| 306 | + case OrderByParameter.ClosestToBay: |
| 307 | + sql += ` ORDER BY (content->'metadata'->'distances'->'bay'->>'meters')::int ASC`; |
| 308 | + break; |
| 309 | + } |
| 310 | + } |
| 311 | + |
| 312 | + sql += ` LIMIT 100`; // Add a reasonable limit |
| 313 | + |
| 314 | + try { |
| 315 | + const { rows } = await (this.dbAdapter as PostgresDatabaseAdapter).query(sql, values); |
| 316 | + return rows.map(row => ({ |
| 317 | + ...row, |
| 318 | + content: typeof row.content === 'string' ? JSON.parse(row.content) : row.content |
| 319 | + })); |
| 320 | + } catch (error) { |
| 321 | + elizaLogger.error('Error in searchLandByMetadataV2:', { |
| 322 | + error: error instanceof Error ? error.message : String(error), |
| 323 | + params |
| 324 | + }); |
| 325 | + throw error; |
| 326 | + } |
| 327 | + } |
169 | 328 |
|
170 | 329 | async getPropertiesByRarityRange(
|
171 | 330 | minRank: number,
|
|
0 commit comments